Merge "Remove obsolete files on preloaded classes."
diff --git a/Android.bp b/Android.bp
index 00b4198..3d087c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -433,11 +433,8 @@
"core/java/android/util/LocalLog.java",
"core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/IndentingPrintWriter.java",
- "core/java/com/android/internal/util/IState.java",
"core/java/com/android/internal/util/MessageUtils.java",
"core/java/com/android/internal/util/RingBufferIndices.java",
- "core/java/com/android/internal/util/State.java",
- "core/java/com/android/internal/util/StateMachine.java",
"core/java/com/android/internal/util/WakeupMessage.java",
"core/java/com/android/internal/util/TokenBucket.java",
],
@@ -566,6 +563,7 @@
"android.hardware.vibrator-V1.3-java",
"framework-protos",
"art.module.public.api",
+ "sdk_module-lib_current_framework-tethering",
// There are a few classes from modules used by the core that
// need to be resolved by metalava. We use a prebuilt stub of the
// full sdk to ensure we can resolve them. If a new class gets added,
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 44c55c2..d090296 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -318,6 +318,7 @@
defaults: ["android-non-updatable_defaults_stubs_current"],
srcs: [":module-lib-api-stubs-docs-non-updatable"],
libs: [
+ "sdk_module-lib_current_framework-tethering",
"sdk_system_current_android",
// NOTE: The below can be removed once the prebuilt stub contains IKE.
"sdk_system_current_android.net.ipsec.ike",
diff --git a/apex/blobstore/README.md b/apex/blobstore/README.md
new file mode 100644
index 0000000..69af436
--- /dev/null
+++ b/apex/blobstore/README.md
@@ -0,0 +1,125 @@
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+-->
+
+# BlobStore Manager
+
+## Introduction
+* BlobStoreManager is a system service added in Android R release that facilitates sharing of
+ data blobs among apps.
+* Apps that would like to share data blobs with other apps can do so by contributing those
+ data blobs with the System and can choose how they would like the System to share the data blobs
+ with other apps.
+* Apps can access data blobs shared by other apps from the System using checksum of the data blobs
+ (plus some other data attributes. More details [below](#blob-handle)).
+* The APIs provided by the BlobStoreManager are meant to reduce storage and network usage by
+ reusing the data available on the device instead of downloading the same data again and having
+ multiple copies of the same data on disk.
+* It is not meant to provide access to the data which apps otherwise would not be able to access.
+ In other words, if an app’s only means of obtaining access to certain data is through
+ BlobStoreManager, then that use case is not really intended or supported.
+* For example, if earlier an app was downloading certain shared data from a server, then by using
+ BlobStoreManager, it can first check whether or not the data is already available on the device
+ before downloading.
+
+## Concepts
+### Blob handle
+Blob handle is the identifier of the data and it is what apps need to use for referring to the
+data blobs. Currently, this is made of following bits of information:
+* SHA256 checksum of data
+* Data label: A user readable string that indicates what the data blob is.
+ This is meant to be used when surfacing a list of blobs to the user.
+* Data expiry time: A timestamp after which the data blob should be considered invalid and not
+ allowed to be accessed by any app.
+* Data tag: An opaque string associated with the blob. System does not interpret this in any way or
+ use it for any purposes other than when checking whether two Blob handle identifiers are referring
+ to the same data blob. This is meant to be used by the apps, either for categorization for
+ data blobs or for adding additional identifiers. For example, an app can add tags like
+ *machine_learning* or *media* depending on the data blob if necessary.
+
+When comparing two Blob handles, the System will compare all the pieces of information above and
+only when two Blob handles are equal, the data blobs corresponding to those identifiers are
+considered equal.
+
+### Blob sharing session
+Session is a way to allow apps to contribute data over multiple time intervals. Each session is
+associated with a unique Identifier that is created and obtained by the apps by calling
+[BlobStoreManager#createSession](https://developer.android.com/reference/android/app/blob/BlobStoreManager#createSession(android.app.blob.BlobHandle)).
+Apps can save the Identifier associated with a session and use it to open and close it
+multiple times for contributing the data. For example, if an app is downloading
+some content over the network, it can start a Session and start contributing this data to the
+System immediately and if the network connection is lost for any reason, the app can close this
+session. When the download resumes, the app can reopen the session and start contributing again.
+Note that once the entire data is contributed, the app has no reason to hold on to the Session Id.
+
+### Blob commit
+Since a data blob can be contributed in a session over multiple time intervals, an app closing a
+session does not imply that the contribution is completed. So, *commit* is added as an explicit
+event / signal for the app to indicate that the contribution of the data blob is completed.
+At this point, the System can verify the data blob does indeed correspond to the Blob handle used
+by the app and prevent the app from making any further modifications to the data blob. Once the
+data blob is committed and verified by the System, it is available for other applications to access.
+
+### Access modes
+When an application contributes a data blob to the System, it can choose to specify how it would
+like the System to share this data blob with other applications. Access modes refer to the type of
+access that apps specified when contributing a data blob. As of Android S release, there are
+four access modes:
+* Allow specific packages: Apps can specify a specific set of applications that are allowed to
+ access their data blob.
+* Allow packages with the same signature: Apps can specify that only the applications that are
+ signed with the same certificate as them can access their data blob.
+* Allow public access: Apps can specify that any other app on the device can access their data blob.
+* Allow private access: Apps can specify that no other app can access their data blob unless they
+ happen to contribute the same data blob.
+ * Note that in this case, two apps might download the same data blob and contribute to the System
+ in which case we are not saving anything in terms of bandwidth usage, but we would still be
+ saving disk usage since we would be keeping only one copy of data on disk.
+
+### Lease
+Leasing a blob is a way to specify that an application is interested in using a data blob
+and would like the System to not delete this data blob. Applications can also access a blob
+without holding a lease on it, in which case the System can choose to delete the data blob at any
+time. So, if an application wants to make sure a data blob is available for access for a certain
+period, it is recommended that the application acquire a lease on the data blob. Applications can
+either specify upfront how long they would like to hold the lease for (which is called the lease
+expiry time), or they can acquire a lease without specifying a time period and release the lease
+when they are done with the data blob.
+
+## Sharing data blobs across users
+By default, data blobs are only accessible to applications in the user in which the data blob was
+contributed, but if an application holds the permission
+[ACCESS_BLOBS_ACROSS_USERS](https://developer.android.com/reference/android/Manifest.permission#ACCESS_BLOBS_ACROSS_USERS),
+then they are allowed to access blobs that are contributed by the applications in the other users.
+As of Android S, this permission is only available to following set of applications:
+* Apps signed with the platform certificate
+* Privileged applications
+* Applications holding the
+ [ASSISTANT](https://developer.android.com/reference/android/app/role/RoleManager#ROLE_ASSISTANT)
+ role
+* Development applications
+
+Note that the access modes that applications choose while committing the data blobs still apply
+when these data blobs are accessed across users. So for example, if *appA* contributed a
+data blob in *user0* and specified to share this data blob with only a specific set of
+applications [*appB*, *appC*], then *appD* on *user10* will not be able to access this data blob
+even if the app is granted the `ACCESS_BLOBS_ACROSS_USERS` permission.
+
+When apps that are allowed to access blobs across users
+(i.e. those holding the permission `ACCESS_BLOBS_ACROSS_USERS`) try to access a data blob,
+they can do so as if it is any other data blob. In other words, the applications don’t need to
+know where the data blob is contributed, because the System will automatically check and will
+allow access if this data blob is available either on the user in which the calling application
+is running in or other users.
\ No newline at end of file
diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS
index 69dfcc9..062ffd4 100644
--- a/cmds/idmap2/OWNERS
+++ b/cmds/idmap2/OWNERS
@@ -1,4 +1,4 @@
set noparent
toddke@google.com
-rtmitchell@google.com
-patb@google.com
\ No newline at end of file
+patb@google.com
+zyy@google.com
diff --git a/config/README.md b/config/README.md
new file mode 100644
index 0000000..450a5c6
--- /dev/null
+++ b/config/README.md
@@ -0,0 +1,13 @@
+# Configuration files for ART compiling the framework
+
+* boot-image-profile.txt: A list of methods from the boot classpath to be compiled by dex2oat.
+ The order in the file is not relevant.
+* boot-profile.txt: An ordered list of methods from the boot classpath to be compiled by
+ the JIT in the order provided in the file. Used by JIT zygote, when on-device
+ signing failed.
+* dirty-image-objects: List of objects in the boot image which are known to
+ become dirty. This helps binning objects in the image file.
+* preloaded-classes: classes that will be allocated in the boot image, and
+ initialized by the zygote.
+* preloaded-classes-denylist: Classes that should not be initialized in the
+ zygote, as they have app-specific behavior.
diff --git a/core/api/Android.bp b/core/api/Android.bp
index 170febb..114a957 100644
--- a/core/api/Android.bp
+++ b/core/api/Android.bp
@@ -51,11 +51,17 @@
filegroup {
name: "non-updatable-module-lib-current.txt",
srcs: ["module-lib-current.txt"],
- visibility: ["//frameworks/base/api"],
+ visibility: [
+ "//frameworks/base/api",
+ "//cts/tests/signature/api",
+ ],
}
filegroup {
name: "non-updatable-module-lib-removed.txt",
srcs: ["module-lib-removed.txt"],
- visibility: ["//frameworks/base/api"],
+ visibility: [
+ "//frameworks/base/api",
+ "//cts/tests/signature/api",
+ ],
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 9d1a171..087b54e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -31427,6 +31427,8 @@
method @Nullable public double[] createDoubleArray();
method @Nullable public float[] createFloatArray();
method @Nullable public int[] createIntArray();
+ method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>);
+ method @Nullable public <T extends android.os.IInterface> java.util.ArrayList<T> createInterfaceArrayList(@NonNull java.util.function.Function<android.os.IBinder,T>);
method @Nullable public long[] createLongArray();
method @Nullable public String[] createStringArray();
method @Nullable public java.util.ArrayList<java.lang.String> createStringArrayList();
@@ -31444,9 +31446,9 @@
method public byte[] marshall();
method @NonNull public static android.os.Parcel obtain();
method @NonNull public static android.os.Parcel obtain(@NonNull android.os.IBinder);
- method @Nullable public Object[] readArray(@Nullable ClassLoader);
+ method @Deprecated @Nullable public Object[] readArray(@Nullable ClassLoader);
method @Nullable public <T> T[] readArray(@Nullable ClassLoader, @NonNull Class<T>);
- method @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader);
+ method @Deprecated @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader);
method @Nullable public <T> java.util.ArrayList<T> readArrayList(@Nullable ClassLoader, @NonNull Class<? extends T>);
method public void readBinderArray(@NonNull android.os.IBinder[]);
method public void readBinderList(@NonNull java.util.List<android.os.IBinder>);
@@ -31464,28 +31466,32 @@
method public android.os.ParcelFileDescriptor readFileDescriptor();
method public float readFloat();
method public void readFloatArray(@NonNull float[]);
- method @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
+ method @Deprecated @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
+ method @Nullable public <K, V> java.util.HashMap<K,V> readHashMap(@Nullable ClassLoader, @NonNull Class<? extends K>, @NonNull Class<? extends V>);
method public int readInt();
method public void readIntArray(@NonNull int[]);
- method public void readList(@NonNull java.util.List, @Nullable ClassLoader);
+ method public <T extends android.os.IInterface> void readInterfaceArray(@NonNull T[], @NonNull java.util.function.Function<android.os.IBinder,T>);
+ method public <T extends android.os.IInterface> void readInterfaceList(@NonNull java.util.List<T>, @NonNull java.util.function.Function<android.os.IBinder,T>);
+ method @Deprecated public void readList(@NonNull java.util.List, @Nullable ClassLoader);
method public <T> void readList(@NonNull java.util.List<? super T>, @Nullable ClassLoader, @NonNull Class<T>);
method public long readLong();
method public void readLongArray(@NonNull long[]);
- method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
- method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
+ method @Deprecated public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
+ method public <K, V> void readMap(@NonNull java.util.Map<? super K,? super V>, @Nullable ClassLoader, @NonNull Class<K>, @NonNull Class<V>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader, @NonNull Class<T>);
method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
method @Nullable public <T> T[] readParcelableArray(@Nullable ClassLoader, @NonNull Class<T>);
- method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
+ method @Deprecated @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>);
method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
method @Nullable public android.os.PersistableBundle readPersistableBundle();
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
- method @Nullable public java.io.Serializable readSerializable();
+ method @Deprecated @Nullable public java.io.Serializable readSerializable();
method @Nullable public <T extends java.io.Serializable> T readSerializable(@Nullable ClassLoader, @NonNull Class<T>);
method @NonNull public android.util.Size readSize();
method @NonNull public android.util.SizeF readSizeF();
- method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);
+ method @Deprecated @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);
method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader, @NonNull Class<? extends T>);
method @Nullable public android.util.SparseBooleanArray readSparseBooleanArray();
method @Nullable public String readString();
@@ -31519,6 +31525,8 @@
method public void writeFloatArray(@Nullable float[]);
method public void writeInt(int);
method public void writeIntArray(@Nullable int[]);
+ method public <T extends android.os.IInterface> void writeInterfaceArray(@Nullable T[]);
+ method public <T extends android.os.IInterface> void writeInterfaceList(@Nullable java.util.List<T>);
method public void writeInterfaceToken(@NonNull String);
method public void writeList(@Nullable java.util.List);
method public void writeLong(long);
@@ -40696,6 +40704,7 @@
method @NonNull public java.util.List<java.lang.Integer> getBands();
method @NonNull public java.util.List<java.lang.String> getMccMncs();
method public int getPriority();
+ method @NonNull public java.util.List<android.telephony.RadioAccessSpecifier> getRadioAccessSpecifiers();
method public int getSubId();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.AvailableNetworkInfo> CREATOR;
@@ -40704,6 +40713,14 @@
field public static final int PRIORITY_MED = 2; // 0x2
}
+ public static final class AvailableNetworkInfo.Builder {
+ ctor public AvailableNetworkInfo.Builder(int);
+ method @NonNull public android.telephony.AvailableNetworkInfo build();
+ method @NonNull public android.telephony.AvailableNetworkInfo.Builder setMccMncs(@NonNull java.util.List<java.lang.String>);
+ method @NonNull public android.telephony.AvailableNetworkInfo.Builder setPriority(int);
+ method @NonNull public android.telephony.AvailableNetworkInfo.Builder setRadioAccessSpecifiers(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>);
+ }
+
public final class BarringInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.telephony.BarringInfo.BarringServiceInfo getBarringServiceInfo(int);
@@ -40737,11 +40754,11 @@
}
public class CarrierConfigManager {
- method @Nullable public android.os.PersistableBundle getConfig();
- method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int);
- method @Nullable public android.os.PersistableBundle getConfigForSubId(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfig();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigForSubId(int);
method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
- method public void notifyConfigChangedForSubId(int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyConfigChangedForSubId(int);
field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1
field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2
@@ -40812,6 +40829,7 @@
field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool";
field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+ field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool";
field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
field public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int";
@@ -40873,6 +40891,8 @@
field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int";
+ field public static final String KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT = "esim_download_retry_backoff_timer_sec_int";
+ field public static final String KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT = "esim_max_download_retry_attempts_int";
field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
field public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
@@ -40975,6 +40995,7 @@
field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool";
field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+ field public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = "supports_device_to_device_communication_using_dtmf_bool";
@@ -42747,7 +42768,7 @@
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isManualNetworkSelectionAllowed();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isModemEnabledForSlot(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isModemEnabledForSlot(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int isMultiSimSupported();
method public boolean isNetworkRoaming();
method public boolean isRadioInterfaceCapabilitySupported(@NonNull String);
@@ -43453,8 +43474,10 @@
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVtSettingEnabled();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
+ method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
@@ -43471,7 +43494,9 @@
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @NonNull public android.telephony.ims.RcsUceAdapter getUceAdapter();
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE"}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
+ method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
field public static final String ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN = "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
}
@@ -43670,6 +43695,19 @@
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsRegistrationAttributes> CREATOR;
}
+ public abstract class ImsStateCallback {
+ ctor public ImsStateCallback();
+ method public abstract void onAvailable();
+ method public abstract void onError();
+ method public abstract void onUnavailable(int);
+ field public static final int REASON_IMS_SERVICE_DISCONNECTED = 3; // 0x3
+ field public static final int REASON_IMS_SERVICE_NOT_READY = 6; // 0x6
+ field public static final int REASON_NO_IMS_SERVICE_CONFIGURED = 4; // 0x4
+ field public static final int REASON_SUBSCRIPTION_INACTIVE = 5; // 0x5
+ field public static final int REASON_UNKNOWN_PERMANENT_ERROR = 2; // 0x2
+ field public static final int REASON_UNKNOWN_TEMPORARY_ERROR = 1; // 0x1
+ }
+
public class RcsUceAdapter {
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
}
@@ -47523,6 +47561,10 @@
field public static final int KEYCODE_CUT = 277; // 0x115
field public static final int KEYCODE_D = 32; // 0x20
field public static final int KEYCODE_DEL = 67; // 0x43
+ field public static final int KEYCODE_DEMO_APP_1 = 301; // 0x12d
+ field public static final int KEYCODE_DEMO_APP_2 = 302; // 0x12e
+ field public static final int KEYCODE_DEMO_APP_3 = 303; // 0x12f
+ field public static final int KEYCODE_DEMO_APP_4 = 304; // 0x130
field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17
field public static final int KEYCODE_DPAD_DOWN = 20; // 0x14
field public static final int KEYCODE_DPAD_DOWN_LEFT = 269; // 0x10d
@@ -47554,6 +47596,10 @@
field public static final int KEYCODE_F7 = 137; // 0x89
field public static final int KEYCODE_F8 = 138; // 0x8a
field public static final int KEYCODE_F9 = 139; // 0x8b
+ field public static final int KEYCODE_FEATURED_APP_1 = 297; // 0x129
+ field public static final int KEYCODE_FEATURED_APP_2 = 298; // 0x12a
+ field public static final int KEYCODE_FEATURED_APP_3 = 299; // 0x12b
+ field public static final int KEYCODE_FEATURED_APP_4 = 300; // 0x12c
field public static final int KEYCODE_FOCUS = 80; // 0x50
field public static final int KEYCODE_FORWARD = 125; // 0x7d
field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70
@@ -47719,6 +47765,14 @@
field public static final int KEYCODE_U = 49; // 0x31
field public static final int KEYCODE_UNKNOWN = 0; // 0x0
field public static final int KEYCODE_V = 50; // 0x32
+ field public static final int KEYCODE_VIDEO_APP_1 = 289; // 0x121
+ field public static final int KEYCODE_VIDEO_APP_2 = 290; // 0x122
+ field public static final int KEYCODE_VIDEO_APP_3 = 291; // 0x123
+ field public static final int KEYCODE_VIDEO_APP_4 = 292; // 0x124
+ field public static final int KEYCODE_VIDEO_APP_5 = 293; // 0x125
+ field public static final int KEYCODE_VIDEO_APP_6 = 294; // 0x126
+ field public static final int KEYCODE_VIDEO_APP_7 = 295; // 0x127
+ field public static final int KEYCODE_VIDEO_APP_8 = 296; // 0x128
field public static final int KEYCODE_VOICE_ASSIST = 231; // 0xe7
field public static final int KEYCODE_VOLUME_DOWN = 25; // 0x19
field public static final int KEYCODE_VOLUME_MUTE = 164; // 0xa4
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index c3f9c20..3a35f24 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -113,6 +113,7 @@
public class AudioManager {
method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
+ method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BtProfileConnectionInfo);
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean);
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean);
@@ -122,6 +123,19 @@
field public static final int FLAG_FROM_KEY = 4096; // 0x1000
}
+ public final class BtProfileConnectionInfo implements android.os.Parcelable {
+ method @NonNull public static android.media.BtProfileConnectionInfo a2dpInfo(boolean, int);
+ method public int describeContents();
+ method public boolean getIsLeOutput();
+ method public int getProfile();
+ method public boolean getSuppressNoisyIntent();
+ method public int getVolume();
+ method @NonNull public static android.media.BtProfileConnectionInfo hearingAidInfo(boolean);
+ method @NonNull public static android.media.BtProfileConnectionInfo leAudio(boolean, boolean);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.BtProfileConnectionInfo> CREATOR;
+ }
+
public class MediaMetadataRetriever implements java.lang.AutoCloseable {
field public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; // 0x28
}
@@ -297,6 +311,10 @@
method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException;
}
+ public class SystemConfigManager {
+ method @NonNull public java.util.List<android.content.ComponentName> getEnabledComponentOverrides(@NonNull String);
+ }
+
}
package android.os.storage {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ac6943c..84a4a44 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8581,7 +8581,6 @@
public class SystemConfigManager {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
- method @NonNull public java.util.List<java.lang.String> getEnabledComponentOverrides(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String);
}
@@ -13742,7 +13741,9 @@
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int);
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isSupported() throws android.telephony.ims.ImsException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerFullNetworkRegistration(@NonNull android.telephony.ims.SipDelegateConnection, @IntRange(from=100, to=699) int, @Nullable String);
+ method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
field public static final int DENIED_REASON_INVALID = 4; // 0x4
field public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1; // 0x1
field public static final int DENIED_REASON_NOT_ALLOWED = 2; // 0x2
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 6ccdf91..d0e659b 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2748,7 +2748,7 @@
method public static String actionToString(int);
method public final void setDisplayId(int);
field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800
- field public static final int LAST_KEYCODE = 288; // 0x120
+ field public static final int LAST_KEYCODE = 304; // 0x130
}
public final class KeyboardShortcutGroup implements android.os.Parcelable {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index e08a493..ca9a468 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -343,7 +343,6 @@
filegroup {
name: "framework-telephony-common-shared-srcs",
srcs: [
- ":modules-utils-preconditions-srcs",
"android/os/RegistrantList.java",
"android/os/Registrant.java",
"android/util/IndentingPrintWriter.java",
@@ -355,10 +354,7 @@
"com/android/internal/util/BitwiseInputStream.java",
"com/android/internal/util/FastXmlSerializer.java",
"com/android/internal/util/HexDump.java",
- "com/android/internal/util/IState.java",
"com/android/internal/util/IndentingPrintWriter.java",
- "com/android/internal/util/State.java",
- "com/android/internal/util/StateMachine.java",
"com/android/internal/util/UserIcons.java",
],
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index db5dcc5..af59ea1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -77,7 +77,6 @@
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -8788,9 +8787,7 @@
* the activity is visible after the screen is turned on when the lockscreen is up. In addition,
* if this flag is set and the activity calls {@link
* KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
- * the screen will turn on. If the screen is off and device is not secured, this flag can turn
- * screen on and dismiss keyguard to make this activity visible and resume, which can be used to
- * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}
+ * the screen will turn on.
*
* @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise.
*
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 8aa2785..5143579 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -552,6 +552,11 @@
inflateAsync(rvToApply);
return;
}
+
+ // Prepare a local reference to the remote Context so we're ready to
+ // inflate any requested LayoutParams
+ mRemoteContext = getRemoteContext();
+
int layoutId = rvToApply.getLayoutId();
if (rvToApply.canRecycleView(mView)) {
try {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index dac8ffe..cf00cbd 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2022,6 +2022,7 @@
* {@link BluetoothProfile#HEADSET},
* {@link BluetoothProfile#A2DP},
* {@link BluetoothProfile#HEARING_AID}
+ * {@link BluetoothProfile#LE_AUDIO}
* @return A list of active bluetooth devices
* @throws IllegalArgumentException If profile is not one of {@link ActiveDeviceProfile}
* @hide
@@ -2034,12 +2035,14 @@
public @NonNull List<BluetoothDevice> getActiveDevices(@ActiveDeviceProfile int profile) {
if (profile != BluetoothProfile.HEADSET
&& profile != BluetoothProfile.A2DP
- && profile != BluetoothProfile.HEARING_AID) {
+ && profile != BluetoothProfile.HEARING_AID
+ && profile != BluetoothProfile.LE_AUDIO) {
Log.e(TAG, "Invalid profile param value in getActiveDevices");
throw new IllegalArgumentException("Profiles must be one of "
+ "BluetoothProfile.A2DP, "
+ "BluetoothProfile.HEARING_AID, or"
- + "BluetoothProfile.HEARING_AID");
+ + "BluetoothProfile.HEARING_AID"
+ + "BluetoothProfile.LE_AUDIO");
}
try {
mServiceLock.readLock().lock();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d811040..e781c2f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1147,6 +1147,10 @@
* numbers. Applications can <strong>dial</strong> emergency numbers using
* {@link #ACTION_DIAL}, however.
*
+ * <p>Note: An app filling the {@link android.app.role.RoleManager#ROLE_DIALER} role should use
+ * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls rather than
+ * relying on this intent.
+ *
* <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M}
* and above and declares as using the {@link android.Manifest.permission#CALL_PHONE}
* permission which is not granted, then attempting to use this action will
diff --git a/core/java/android/content/om/OWNERS b/core/java/android/content/om/OWNERS
index 91a0abf..3669817 100644
--- a/core/java/android/content/om/OWNERS
+++ b/core/java/android/content/om/OWNERS
@@ -3,4 +3,4 @@
toddke@android.com
toddke@google.com
patb@google.com
-rtmitchell@google.com
+zyy@google.com
diff --git a/core/java/android/content/res/OWNERS b/core/java/android/content/res/OWNERS
index bc2355c..d12d920 100644
--- a/core/java/android/content/res/OWNERS
+++ b/core/java/android/content/res/OWNERS
@@ -3,4 +3,4 @@
toddke@android.com
toddke@google.com
patb@google.com
-rtmitchell@google.com
+zyy@google.com
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 7ef5bac..8605248 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -232,11 +232,10 @@
ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO);
ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO);
- // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined
- ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S);
}
private static final Set<String> ENABLED_ALGOS =
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 74506da..ee24084 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -777,8 +777,8 @@
}
/**
- * Examine the given template and normalize if it refers to a "merged"
- * mobile subscriber. We pick the "lowest" merged subscriber as the primary
+ * Examine the given template and normalize it.
+ * We pick the "lowest" merged subscriber as the primary
* for key purposes, and expand the template to match all other merged
* subscribers.
* <p>
@@ -793,8 +793,8 @@
}
/**
- * Examine the given template and normalize if it refers to a "merged"
- * mobile subscriber. We pick the "lowest" merged subscriber as the primary
+ * Examine the given template and normalize it.
+ * We pick the "lowest" merged subscriber as the primary
* for key purposes, and expand the template to match all other merged
* subscribers.
*
@@ -806,7 +806,12 @@
* A, but also matches B.
*/
public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) {
- if (!template.isMatchRuleMobile()) return template;
+ // Now there are several types of network which uses SubscriberId to store network
+ // information. For instances:
+ // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network.
+ // The TYPE_CARRIER means that the network associate to specific carrier network.
+
+ if (template.mSubscriberId == null) return template;
for (String[] merged : mergedList) {
if (ArrayUtils.contains(merged, template.mSubscriberId)) {
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 2a344f6..ad3de25 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -103,7 +103,7 @@
* are unparcelled, mParcelledData willbe set to null.
*/
@UnsupportedAppUsage
- Parcel mParcelledData = null;
+ volatile Parcel mParcelledData = null;
/**
* Whether {@link #mParcelledData} was generated by native code or not.
@@ -182,13 +182,56 @@
* @param b a Bundle to be copied.
*/
BaseBundle(BaseBundle b) {
- copyInternal(b, false);
+ this(b, /* deep */ false);
}
/**
- * Special constructor that does not initialize the bundle.
+ * Constructs a {@link BaseBundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
*/
- BaseBundle(boolean doInit) {
+ BaseBundle(BaseBundle from, boolean deep) {
+ synchronized (from) {
+ mClassLoader = from.mClassLoader;
+
+ if (from.mMap != null) {
+ if (!deep) {
+ mMap = new ArrayMap<>(from.mMap);
+ } else {
+ final ArrayMap<String, Object> fromMap = from.mMap;
+ final int n = fromMap.size();
+ mMap = new ArrayMap<>(n);
+ for (int i = 0; i < n; i++) {
+ mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
+ }
+ }
+ } else {
+ mMap = null;
+ }
+
+ final Parcel parcelledData;
+ if (from.mParcelledData != null) {
+ if (from.isEmptyParcel()) {
+ parcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
+ mParcelledByNative = false;
+ } else {
+ parcelledData = Parcel.obtain();
+ parcelledData.appendFrom(from.mParcelledData, 0,
+ from.mParcelledData.dataSize());
+ parcelledData.setDataPosition(0);
+ mParcelledByNative = from.mParcelledByNative;
+ }
+ } else {
+ parcelledData = null;
+ mParcelledByNative = false;
+ }
+
+ // Keep as last statement to ensure visibility of other fields
+ mParcelledData = parcelledData;
+ }
}
/**
@@ -323,8 +366,8 @@
} else {
mMap.erase();
}
- mParcelledData = null;
mParcelledByNative = false;
+ mParcelledData = null;
return;
}
@@ -358,8 +401,8 @@
if (recycleParcel) {
recycleParcel(parcelledData);
}
- mParcelledData = null;
mParcelledByNative = false;
+ mParcelledData = null;
}
if (DEBUG) {
Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
@@ -501,44 +544,7 @@
mMap.clear();
}
- void copyInternal(BaseBundle from, boolean deep) {
- synchronized (from) {
- if (from.mParcelledData != null) {
- if (from.isEmptyParcel()) {
- mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
- mParcelledByNative = false;
- } else {
- mParcelledData = Parcel.obtain();
- mParcelledData.appendFrom(from.mParcelledData, 0,
- from.mParcelledData.dataSize());
- mParcelledData.setDataPosition(0);
- mParcelledByNative = from.mParcelledByNative;
- }
- } else {
- mParcelledData = null;
- mParcelledByNative = false;
- }
-
- if (from.mMap != null) {
- if (!deep) {
- mMap = new ArrayMap<>(from.mMap);
- } else {
- final ArrayMap<String, Object> fromMap = from.mMap;
- final int N = fromMap.size();
- mMap = new ArrayMap<>(N);
- for (int i = 0; i < N; i++) {
- mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
- }
- }
- } else {
- mMap = null;
- }
-
- mClassLoader = from.mClassLoader;
- }
- }
-
- Object deepCopyValue(Object value) {
+ private Object deepCopyValue(Object value) {
if (value == null) {
return null;
}
@@ -570,7 +576,7 @@
return value;
}
- ArrayList deepcopyArrayList(ArrayList from) {
+ private ArrayList deepcopyArrayList(ArrayList from) {
final int N = from.size();
ArrayList out = new ArrayList(N);
for (int i=0; i<N; i++) {
@@ -1717,9 +1723,9 @@
if (length < 0) {
throw new RuntimeException("Bad length in parcel: " + length);
} else if (length == 0) {
+ mParcelledByNative = false;
// Empty Bundle or end of data.
mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
- mParcelledByNative = false;
return;
} else if (length % 4 != 0) {
throw new IllegalStateException("Bundle length is not aligned by 4: " + length);
@@ -1757,8 +1763,8 @@
+ ": " + length + " bundle bytes starting at " + offset);
p.setDataPosition(0);
- mParcelledData = p;
mParcelledByNative = isNativeBundle;
+ mParcelledData = p;
}
/** {@hide} */
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 92eb7a5..b2bbfd6 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -102,6 +102,18 @@
}
/**
+ * Constructs a {@link Bundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
+ */
+ Bundle(Bundle from, boolean deep) {
+ super(from, deep);
+ }
+
+ /**
* If {@link #mParcelledData} is not null, copy the HAS FDS bit from it because it's fast.
* Otherwise (if {@link #mParcelledData} is already null), leave {@link #FLAG_HAS_FDS_KNOWN}
* unset, because scanning a map is slower. We'll do it lazily in
@@ -167,13 +179,6 @@
}
/**
- * Constructs a Bundle without initializing it.
- */
- Bundle(boolean doInit) {
- super(doInit);
- }
-
- /**
* Make a Bundle for a single key/value pair.
*
* @hide
@@ -260,9 +265,7 @@
* are referenced as-is and not copied in any way.
*/
public Bundle deepCopy() {
- Bundle b = new Bundle(false);
- b.copyInternal(this, true);
- return b;
+ return new Bundle(this, /* deep */ true);
}
/**
@@ -324,28 +327,10 @@
*/
public boolean hasFileDescriptors() {
if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
- boolean fdFound = false; // keep going until we find one or run out of data
-
- if (mParcelledData != null) {
- if (mParcelledData.hasFileDescriptors()) {
- fdFound = true;
- }
- } else {
- // It's been unparcelled, so we need to walk the map
- for (int i=mMap.size()-1; i>=0; i--) {
- Object obj = mMap.valueAt(i);
- if (Parcel.hasFileDescriptors(obj)) {
- fdFound = true;
- break;
- }
- }
- }
-
- if (fdFound) {
- mFlags |= FLAG_HAS_FDS;
- } else {
- mFlags &= ~FLAG_HAS_FDS;
- }
+ Parcel p = mParcelledData;
+ mFlags = (Parcel.hasFileDescriptors((p != null) ? p : mMap))
+ ? mFlags | FLAG_HAS_FDS
+ : mFlags & ~FLAG_HAS_FDS;
mFlags |= FLAG_HAS_FDS_KNOWN;
}
return (mFlags & FLAG_HAS_FDS) != 0;
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index d83d94a..15e3ce2 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.content.ComponentName;
+
/**
* Binder interface to query SystemConfig in the system server.
* {@hide}
@@ -44,5 +46,5 @@
/**
* @see SystemConfigManager#getEnabledComponentOverrides
*/
- List<String> getEnabledComponentOverrides(String packageName);
+ List<ComponentName> getEnabledComponentOverrides(String packageName);
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index dd0cb8c..7bdb6b9 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -62,6 +62,8 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.function.Function;
+import java.util.function.IntFunction;
import java.util.function.Supplier;
/**
@@ -178,8 +180,12 @@
* {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()},
* {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])},
* {@link #createBinderArray()},
+ * {@link #writeInterfaceArray(T[])}, {@link #readInterfaceArray(T[], Function)},
+ * {@link #createInterfaceArray(IntFunction, Function)},
* {@link #writeBinderList(List)}, {@link #readBinderList(List)},
- * {@link #createBinderArrayList()}.</p>
+ * {@link #createBinderArrayList()},
+ * {@link #writeInterfaceList(List)}, {@link #readInterfaceList(List, Function)},
+ * {@link #createInterfaceArrayList(Function)}.</p>
*
* <p>FileDescriptor objects, representing raw Linux file descriptor identifiers,
* can be written and {@link ParcelFileDescriptor} objects returned to operate
@@ -747,57 +753,70 @@
}
/**
- * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)}
- * has file descriptors.
+ * Check if the object has file descriptors.
+ *
+ * <p>Objects supported are {@link Parcel} and objects that can be passed to {@link
+ * #writeValue(Object)}}
*
* <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method
* for that.
*
- * @throws IllegalArgumentException if you provide any object not supported by above methods.
- * Most notably, if you pass {@link Parcel}, this method will throw, for that check
- * {@link Parcel#hasFileDescriptors()}
+ * @throws IllegalArgumentException if you provide any object not supported by above methods
+ * (including if the unsupported object is inside a nested container).
*
* @hide
*/
public static boolean hasFileDescriptors(Object value) {
- if (value instanceof LazyValue) {
- return ((LazyValue) value).hasFileDescriptors();
- } else if (value instanceof Parcelable) {
- if ((((Parcelable) value).describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+ if (value instanceof Parcel) {
+ Parcel parcel = (Parcel) value;
+ if (parcel.hasFileDescriptors()) {
return true;
}
- } else if (value instanceof Parcelable[]) {
- Parcelable[] array = (Parcelable[]) value;
- for (int n = array.length - 1; n >= 0; n--) {
- Parcelable p = array[n];
- if (p != null && ((p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
+ } else if (value instanceof LazyValue) {
+ LazyValue lazy = (LazyValue) value;
+ if (lazy.hasFileDescriptors()) {
+ return true;
+ }
+ } else if (value instanceof Parcelable) {
+ Parcelable parcelable = (Parcelable) value;
+ if ((parcelable.describeContents() & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+ return true;
+ }
+ } else if (value instanceof ArrayMap<?, ?>) {
+ ArrayMap<?, ?> map = (ArrayMap<?, ?>) value;
+ for (int i = 0, n = map.size(); i < n; i++) {
+ if (hasFileDescriptors(map.keyAt(i))
+ || hasFileDescriptors(map.valueAt(i))) {
+ return true;
+ }
+ }
+ } else if (value instanceof Map<?, ?>) {
+ Map<?, ?> map = (Map<?, ?>) value;
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
+ if (hasFileDescriptors(entry.getKey())
+ || hasFileDescriptors(entry.getValue())) {
+ return true;
+ }
+ }
+ } else if (value instanceof List<?>) {
+ List<?> list = (List<?>) value;
+ for (int i = 0, n = list.size(); i < n; i++) {
+ if (hasFileDescriptors(list.get(i))) {
return true;
}
}
} else if (value instanceof SparseArray<?>) {
SparseArray<?> array = (SparseArray<?>) value;
- for (int n = array.size() - 1; n >= 0; n--) {
- Object object = array.valueAt(n);
- if (object instanceof Parcelable) {
- Parcelable p = (Parcelable) object;
- if (p != null && (p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
- return true;
- }
+ for (int i = 0, n = array.size(); i < n; i++) {
+ if (hasFileDescriptors(array.valueAt(i))) {
+ return true;
}
}
- } else if (value instanceof ArrayList<?>) {
- ArrayList<?> array = (ArrayList<?>) value;
- for (int n = array.size() - 1; n >= 0; n--) {
- Object object = array.get(n);
- if (object instanceof Parcelable) {
- Parcelable p = (Parcelable) object;
- if (p != null && ((p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
- return true;
- }
+ } else if (value instanceof Object[]) {
+ Object[] array = (Object[]) value;
+ for (int i = 0, n = array.length; i < n; i++) {
+ if (hasFileDescriptors(array[i])) {
+ return true;
}
}
} else {
@@ -1717,6 +1736,30 @@
}
/**
+ * Flatten a homogeneous array containing an IInterface type into the parcel,
+ * at the current dataPosition() and growing dataCapacity() if needed. The
+ * type of the objects in the array must be one that implements IInterface.
+ *
+ * @param val The array of objects to be written.
+ *
+ * @see #createInterfaceArray
+ * @see #readInterfaceArray
+ * @see IInterface
+ */
+ public final <T extends IInterface> void writeInterfaceArray(
+ @SuppressLint("ArrayReturn") @Nullable T[] val) {
+ if (val != null) {
+ int N = val.length;
+ writeInt(N);
+ for (int i=0; i<N; i++) {
+ writeStrongInterface(val[i]);
+ }
+ } else {
+ writeInt(-1);
+ }
+ }
+
+ /**
* @hide
*/
public final void writeCharSequenceArray(@Nullable CharSequence[] val) {
@@ -1772,6 +1815,50 @@
}
/**
+ * Read and return a new array of T (IInterface) from the parcel.
+ *
+ * @return the IInterface array of type T
+ * @param newArray a function to create an array of T with a given length
+ * @param asInterface a function to convert IBinder object into T (IInterface)
+ */
+ @SuppressLint({"ArrayReturn", "NullableCollection", "SamShouldBeLast"})
+ @Nullable
+ public final <T extends IInterface> T[] createInterfaceArray(
+ @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
+ int N = readInt();
+ if (N >= 0) {
+ T[] val = newArray.apply(N);
+ for (int i=0; i<N; i++) {
+ val[i] = asInterface.apply(readStrongBinder());
+ }
+ return val;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Read an array of T (IInterface) from a parcel.
+ *
+ * @param asInterface a function to convert IBinder object into T (IInterface)
+ *
+ * @throws BadParcelableException Throws BadParcelableException if the length of `val`
+ * mismatches the number of items in the parcel.
+ */
+ public final <T extends IInterface> void readInterfaceArray(
+ @SuppressLint("ArrayReturn") @NonNull T[] val,
+ @NonNull Function<IBinder, T> asInterface) {
+ int N = readInt();
+ if (N == val.length) {
+ for (int i=0; i<N; i++) {
+ val[i] = asInterface.apply(readStrongBinder());
+ }
+ } else {
+ throw new BadParcelableException("bad array lengths");
+ }
+ }
+
+ /**
* Flatten a List containing a particular object type into the parcel, at
* the current dataPosition() and growing dataCapacity() if needed. The
* type of the objects in the list must be one that implements Parcelable.
@@ -1885,6 +1972,28 @@
}
/**
+ * Flatten a {@code List} containing T (IInterface) objects into this parcel
+ * at the current position. They can later be retrieved with
+ * {@link #createInterfaceArrayList} or {@link #readInterfaceList}.
+ *
+ * @see #createInterfaceArrayList
+ * @see #readInterfaceList
+ */
+ public final <T extends IInterface> void writeInterfaceList(@Nullable List<T> val) {
+ if (val == null) {
+ writeInt(-1);
+ return;
+ }
+ int N = val.size();
+ int i=0;
+ writeInt(N);
+ while (i < N) {
+ writeStrongInterface(val.get(i));
+ i++;
+ }
+ }
+
+ /**
* Flatten a {@code List} containing arbitrary {@code Parcelable} objects into this parcel
* at the current position. They can later be retrieved using
* {@link #readParcelableList(List, ClassLoader)} if required.
@@ -2881,17 +2990,45 @@
* Please use {@link #readBundle(ClassLoader)} instead (whose data must have
* been written with {@link #writeBundle}. Read into an existing Map object
* from the parcel at the current dataPosition().
+ *
+ * @deprecated Consider using {@link #readBundle(ClassLoader)} as stated above, in case this
+ * method is still preferred use the type-safer version {@link #readMap(Map, ClassLoader,
+ * Class, Class)} starting from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
public final void readMap(@NonNull Map outVal, @Nullable ClassLoader loader) {
- int N = readInt();
- readMapInternal(outVal, N, loader);
+ int n = readInt();
+ readMapInternal(outVal, n, loader, /* clazzKey */ null, /* clazzValue */ null);
+ }
+
+ /**
+ * Same as {@link #readMap(Map, ClassLoader)} but accepts {@code clazzKey} and
+ * {@code clazzValue} parameter as the types required for each key and value pair.
+ *
+ * @throws BadParcelableException If the item to be deserialized is not an instance of that
+ * class or any of its children class
+ */
+ public <K, V> void readMap(@NonNull Map<? super K, ? super V> outVal,
+ @Nullable ClassLoader loader, @NonNull Class<K> clazzKey,
+ @NonNull Class<V> clazzValue) {
+ Objects.requireNonNull(clazzKey);
+ Objects.requireNonNull(clazzValue);
+ int n = readInt();
+ readMapInternal(outVal, n, loader, clazzKey, clazzValue);
}
/**
* Read into an existing List object from the parcel at the current
* dataPosition(), using the given class loader to load any enclosed
* Parcelables. If it is null, the default class loader is used.
+ *
+ * @deprecated Use the type-safer version {@link #readList(List, ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to
+ * use {@link #readTypedList(List, Parcelable.Creator)} if possible (eg. if the items'
+ * class is final) since this is also more performant. Note that changing to the latter
+ * also requires changing the writes.
*/
+ @Deprecated
public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) {
int N = readInt();
readListInternal(outVal, N, loader, /* clazz */ null);
@@ -2918,20 +3055,46 @@
* object from the parcel at the current dataPosition(), using the given
* class loader to load any enclosed Parcelables. Returns null if
* the previously written map object was null.
+ *
+ * @deprecated Consider using {@link #readBundle(ClassLoader)} as stated above, in case this
+ * method is still preferred use the type-safer version {@link #readHashMap(ClassLoader,
+ * Class, Class)} starting from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
- public final HashMap readHashMap(@Nullable ClassLoader loader)
- {
- int N = readInt();
- if (N < 0) {
+ public HashMap readHashMap(@Nullable ClassLoader loader) {
+ int n = readInt();
+ if (n < 0) {
return null;
}
- HashMap m = new HashMap(N);
- readMapInternal(m, N, loader);
+ HashMap m = new HashMap(n);
+ readMapInternal(m, n, loader, /* clazzKey */ null, /* clazzValue */ null);
return m;
}
/**
+ * Same as {@link #readHashMap(ClassLoader)} but accepts {@code clazzKey} and
+ * {@code clazzValue} parameter as the types required for each key and value pair.
+ *
+ * @throws BadParcelableException if the item to be deserialized is not an instance of that
+ * class or any of its children class
+ */
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ @Nullable
+ public <K, V> HashMap<K, V> readHashMap(@Nullable ClassLoader loader,
+ @NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) {
+ Objects.requireNonNull(clazzKey);
+ Objects.requireNonNull(clazzValue);
+ int n = readInt();
+ if (n < 0) {
+ return null;
+ }
+ HashMap<K, V> map = new HashMap<>(n);
+ readMapInternal(map, n, loader, clazzKey, clazzValue);
+ return map;
+ }
+
+ /**
* Read and return a new Bundle object from the parcel at the current
* dataPosition(). Returns null if the previously written Bundle object was
* null.
@@ -3100,7 +3263,14 @@
* dataPosition(). Returns null if the previously written list object was
* null. The given class loader will be used to load any enclosed
* Parcelables.
+ *
+ * @deprecated Use the type-safer version {@link #readArrayList(ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to
+ * use {@link #createTypedArrayList(Parcelable.Creator)} if possible (eg. if the items'
+ * class is final) since this is also more performant. Note that changing to the latter
+ * also requires changing the writes.
*/
+ @Deprecated
@Nullable
public ArrayList readArrayList(@Nullable ClassLoader loader) {
return readArrayListInternal(loader, /* clazz */ null);
@@ -3127,7 +3297,14 @@
* dataPosition(). Returns null if the previously written array was
* null. The given class loader will be used to load any enclosed
* Parcelables.
+ *
+ * @deprecated Use the type-safer version {@link #readArray(ClassLoader, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to use
+ * {@link #createTypedArray(Parcelable.Creator)} if possible (eg. if the items' class is
+ * final) since this is also more performant. Note that changing to the latter also
+ * requires changing the writes.
*/
+ @Deprecated
@Nullable
public Object[] readArray(@Nullable ClassLoader loader) {
return readArrayInternal(loader, /* clazz */ null);
@@ -3153,7 +3330,14 @@
* dataPosition(). Returns null if the previously written list object was
* null. The given class loader will be used to load any enclosed
* Parcelables.
+ *
+ * @deprecated Use the type-safer version {@link #readSparseArray(ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to
+ * use {@link #createTypedSparseArray(Parcelable.Creator)} if possible (eg. if the items'
+ * class is final) since this is also more performant. Note that changing to the latter
+ * also requires changing the writes.
*/
+ @Deprecated
@Nullable
public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) {
return readSparseArrayInternal(loader, /* clazz */ null);
@@ -3367,6 +3551,32 @@
}
/**
+ * Read and return a new ArrayList containing T (IInterface) objects from
+ * the parcel that was written with {@link #writeInterfaceList} at the
+ * current dataPosition(). Returns null if the
+ * previously written list object was null.
+ *
+ * @return A newly created ArrayList containing T (IInterface)
+ *
+ * @see #writeInterfaceList
+ */
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ @Nullable
+ public final <T extends IInterface> ArrayList<T> createInterfaceArrayList(
+ @NonNull Function<IBinder, T> asInterface) {
+ int N = readInt();
+ if (N < 0) {
+ return null;
+ }
+ ArrayList<T> l = new ArrayList<T>(N);
+ while (N > 0) {
+ l.add(asInterface.apply(readStrongBinder()));
+ N--;
+ }
+ return l;
+ }
+
+ /**
* Read into the given List items String objects that were written with
* {@link #writeStringList} at the current dataPosition().
*
@@ -3409,6 +3619,28 @@
}
/**
+ * Read into the given List items IInterface objects that were written with
+ * {@link #writeInterfaceList} at the current dataPosition().
+ *
+ * @see #writeInterfaceList
+ */
+ public final <T extends IInterface> void readInterfaceList(@NonNull List<T> list,
+ @NonNull Function<IBinder, T> asInterface) {
+ int M = list.size();
+ int N = readInt();
+ int i = 0;
+ for (; i < M && i < N; i++) {
+ list.set(i, asInterface.apply(readStrongBinder()));
+ }
+ for (; i<N; i++) {
+ list.add(asInterface.apply(readStrongBinder()));
+ }
+ for (; i<M; i++) {
+ list.remove(N);
+ }
+ }
+
+ /**
* Read the list of {@code Parcelable} objects at the current data position into the
* given {@code list}. The contents of the {@code list} are replaced. If the serialized
* list was {@code null}, {@code list} is cleared.
@@ -3912,7 +4144,13 @@
* object has been written.
* @throws BadParcelableException Throws BadParcelableException if there
* was an error trying to instantiate the Parcelable.
+ *
+ * @deprecated Use the type-safer version {@link #readParcelable(ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to
+ * use {@link Parcelable.Creator#createFromParcel(Parcel)} if possible since this is also
+ * more performant. Note that changing to the latter also requires changing the writes.
*/
+ @Deprecated
@Nullable
public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
return readParcelableInternal(loader, /* clazz */ null);
@@ -3981,7 +4219,11 @@
* read the {@link Parcelable.Creator}.
*
* @see #writeParcelableCreator
+ *
+ * @deprecated Use the type-safer version {@link #readParcelableCreator(ClassLoader, Class)}
+ * starting from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
return readParcelableCreatorInternal(loader, /* clazz */ null);
@@ -4142,7 +4384,11 @@
* Read and return a new Serializable object from the parcel.
* @return the Serializable object, or null if the Serializable name
* wasn't found in the parcel.
+ *
+ * @deprecated Use the type-safer version {@link #readSerializable(ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
public Serializable readSerializable() {
return readSerializableInternal(/* loader */ null, /* clazz */ null);
@@ -4315,13 +4561,23 @@
destroy();
}
- /* package */ void readMapInternal(@NonNull Map outVal, int N,
+ /**
+ * To be replaced by {@link #readMapInternal(Map, int, ClassLoader, Class, Class)}, but keep
+ * the old API for compatibility usages.
+ */
+ /* package */ void readMapInternal(@NonNull Map outVal, int n,
@Nullable ClassLoader loader) {
- while (N > 0) {
- Object key = readValue(loader);
- Object value = readValue(loader);
+ readMapInternal(outVal, n, loader, /* clazzKey */null, /* clazzValue */null);
+ }
+
+ /* package */ <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal, int n,
+ @Nullable ClassLoader loader, @Nullable Class<K> clazzKey,
+ @Nullable Class<V> clazzValue) {
+ while (n > 0) {
+ K key = readValue(loader, clazzKey);
+ V value = readValue(loader, clazzValue);
outVal.put(key, value);
- N--;
+ n--;
}
}
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 7b55e710..f4edcb1 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -156,10 +156,15 @@
}
/**
- * Constructs a PersistableBundle without initializing it.
+ * Constructs a {@link PersistableBundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
*/
- PersistableBundle(boolean doInit) {
- super(doInit);
+ PersistableBundle(PersistableBundle from, boolean deep) {
+ super(from, deep);
}
/**
@@ -190,9 +195,7 @@
* are referenced as-is and not copied in any way.
*/
public PersistableBundle deepCopy() {
- PersistableBundle b = new PersistableBundle(false);
- b.copyInternal(this, true);
- return b;
+ return new PersistableBundle(this, /* deep */ true);
}
/**
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 4e8418b..ba5ed43 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -298,6 +298,17 @@
}
/**
+ * Register callback for service registration notifications.
+ *
+ * @throws RemoteException for underlying error.
+ * @hide
+ */
+ public static void registerForNotifications(
+ @NonNull String name, @NonNull IServiceCallback callback) throws RemoteException {
+ getIServiceManager().registerForNotifications(name, callback);
+ }
+
+ /**
* Return a list of all currently running services.
* @return an array of all currently running services, or <code>null</code> in
* case of an exception
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 3739040..2dcf674 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -78,7 +78,7 @@
public void registerForNotifications(String name, IServiceCallback cb)
throws RemoteException {
- throw new RemoteException();
+ mServiceManager.registerForNotifications(name, cb);
}
public void unregisterForNotifications(String name, IServiceCallback cb)
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index a6316df..cde2063 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -17,10 +17,10 @@
import android.Manifest;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.content.ComponentName;
import android.content.Context;
import android.util.ArraySet;
import android.util.Log;
@@ -138,9 +138,9 @@
* @return The enabled component
* {@hide}
*/
- @SystemApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
- public List<String> getEnabledComponentOverrides(@NonNull String packageName) {
+ public List<ComponentName> getEnabledComponentOverrides(@NonNull String packageName) {
try {
return mInterface.getEnabledComponentOverrides(packageName);
} catch (RemoteException e) {
diff --git a/core/java/android/os/health/HealthStats.java b/core/java/android/os/health/HealthStats.java
index 74ce515..6c648f1 100644
--- a/core/java/android/os/health/HealthStats.java
+++ b/core/java/android/os/health/HealthStats.java
@@ -32,7 +32,7 @@
* Each of the keys references data in one of five data types:
*
* <p>
- * A <b>measurement</b> metric contains a sinlge {@code long} value. That value may
+ * A <b>measurement</b> metric contains a single {@code long} value. That value may
* be a count, a time, or some other type of value. The unit for a measurement
* (COUNT, MS, etc) will always be in the name of the constant for the key to
* retrieve it. For example, the
diff --git a/core/java/android/os/health/UidHealthStats.java b/core/java/android/os/health/UidHealthStats.java
index afc9d78..488a542 100644
--- a/core/java/android/os/health/UidHealthStats.java
+++ b/core/java/android/os/health/UidHealthStats.java
@@ -43,14 +43,14 @@
/**
* How many milliseconds this statistics report covers in wall-clock time while the
- * device was on battery including both screen-on and screen-off time.
+ * device was on battery including only screen-off time.
*/
@HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 3;
/**
* How many milliseconds this statistics report covers that the CPU was running while the
- * device was on battery including both screen-on and screen-off time.
+ * device was on battery including only screen-off time.
*/
@HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 4;
@@ -65,7 +65,7 @@
/**
* Key for a TimerStat for the times a
- * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK full wake lock}
+ * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock}
* was acquired for this uid.
*/
@HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 8ac5c03..6644f1e 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -622,6 +622,14 @@
public static final String NAMESPACE_GAME_OVERLAY = "game_overlay";
/**
+ * Namespace for Android Virtualization Framework related features accessible by native code.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE =
+ "virtualization_framework_native";
+
+ /**
* Namespace for Constrain Display APIs related features.
*
* @hide
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f3a8b5d..9f3a847 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5365,5 +5365,14 @@
*/
public static final String COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS =
"d2d_sharing_contacts";
+
+ /**
+ * TelephonyProvider column name for NR Advanced calling
+ * Determines if the user has enabled VoNR settings for this subscription.
+ *
+ * @hide
+ */
+ public static final String COLUMN_NR_ADVANCED_CALLING_ENABLED =
+ "nr_advanced_calling_enabled";
}
}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 12bcd8b..b5fe4f5 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -62,6 +62,10 @@
* another buffer allocation and copy, and even more pressure on the gc.
* That means that if your log message is filtered out, you might be doing
* significant work and incurring significant overhead.
+ *
+ * <p>When calling the log methods that take a Throwable parameter,
+ * if any of the throwables in the cause chain is an <code>UnknownHostException</code>,
+ * then the stack trace is not logged.
*/
public final class Log {
/** @hide */
@@ -341,6 +345,9 @@
/**
* Handy function to get a loggable stack trace from a Throwable
+
+ * <p>If any of the throwables in the cause chain is an <code>UnknownHostException</code>,
+ * this returns an empty string.
* @param tr An exception to log
*/
@NonNull
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index cda9b23..ba6f4eb 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -830,13 +830,45 @@
* consuming content. May be consumed by system to set account globally.
*/
public static final int KEYCODE_PROFILE_SWITCH = 288;
+ /** Key code constant: Video Application key #1. */
+ public static final int KEYCODE_VIDEO_APP_1 = 289;
+ /** Key code constant: Video Application key #2. */
+ public static final int KEYCODE_VIDEO_APP_2 = 290;
+ /** Key code constant: Video Application key #3. */
+ public static final int KEYCODE_VIDEO_APP_3 = 291;
+ /** Key code constant: Video Application key #4. */
+ public static final int KEYCODE_VIDEO_APP_4 = 292;
+ /** Key code constant: Video Application key #5. */
+ public static final int KEYCODE_VIDEO_APP_5 = 293;
+ /** Key code constant: Video Application key #6. */
+ public static final int KEYCODE_VIDEO_APP_6 = 294;
+ /** Key code constant: Video Application key #7. */
+ public static final int KEYCODE_VIDEO_APP_7 = 295;
+ /** Key code constant: Video Application key #8. */
+ public static final int KEYCODE_VIDEO_APP_8 = 296;
+ /** Key code constant: Featured Application key #1. */
+ public static final int KEYCODE_FEATURED_APP_1 = 297;
+ /** Key code constant: Featured Application key #2. */
+ public static final int KEYCODE_FEATURED_APP_2 = 298;
+ /** Key code constant: Featured Application key #3. */
+ public static final int KEYCODE_FEATURED_APP_3 = 299;
+ /** Key code constant: Featured Application key #4. */
+ public static final int KEYCODE_FEATURED_APP_4 = 300;
+ /** Key code constant: Demo Application key #1. */
+ public static final int KEYCODE_DEMO_APP_1 = 301;
+ /** Key code constant: Demo Application key #2. */
+ public static final int KEYCODE_DEMO_APP_2 = 302;
+ /** Key code constant: Demo Application key #3. */
+ public static final int KEYCODE_DEMO_APP_3 = 303;
+ /** Key code constant: Demo Application key #4. */
+ public static final int KEYCODE_DEMO_APP_4 = 304;
- /**
+ /**
* Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent.
* @hide
*/
@TestApi
- public static final int LAST_KEYCODE = KEYCODE_PROFILE_SWITCH;
+ public static final int LAST_KEYCODE = KEYCODE_DEMO_APP_4;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8143cf9..ffce461 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -157,6 +157,7 @@
private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats);
private static native long[] nativeGetPhysicalDisplayIds();
+ private static native long nativeGetPrimaryPhysicalDisplayId();
private static native IBinder nativeGetPhysicalDisplayToken(long physicalDisplayId);
private static native IBinder nativeCreateDisplay(String name, boolean secure);
private static native void nativeDestroyDisplay(IBinder displayToken);
@@ -2266,6 +2267,15 @@
}
/**
+ * Exposed to identify the correct display to apply the primary display orientation. Avoid using
+ * for any other purpose.
+ * @hide
+ */
+ public static long getPrimaryPhysicalDisplayId() {
+ return nativeGetPrimaryPhysicalDisplayId();
+ }
+
+ /**
* @hide
*/
public static IBinder getPhysicalDisplayToken(long physicalDisplayId) {
diff --git a/core/java/com/android/internal/compat/OWNERS b/core/java/com/android/internal/compat/OWNERS
index cfd0a4b..ee3086a 100644
--- a/core/java/com/android/internal/compat/OWNERS
+++ b/core/java/com/android/internal/compat/OWNERS
@@ -1,6 +1 @@
-# Use this reviewer by default.
-platform-compat-eng+reviews@google.com
-
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+include tools/platform-compat:/OWNERS
diff --git a/core/java/com/android/internal/view/OWNERS b/core/java/com/android/internal/view/OWNERS
index eb2478f..7a590d0 100644
--- a/core/java/com/android/internal/view/OWNERS
+++ b/core/java/com/android/internal/view/OWNERS
@@ -15,7 +15,7 @@
# WindowManager
per-file AppearanceRegion = file:/services/core/java/com/android/server/wm/OWNERS
-per-file BaseIWIndow.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file BaseIWindow.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file RotationPolicy.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file WindowManagerPolicyThread.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 2959667..26ff192 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -17,7 +17,6 @@
package com.android.server;
import android.os.StrictMode;
-import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
@@ -33,13 +32,6 @@
private static final String TAG = "NetworkManagementSocketTagger";
private static final boolean LOGD = false;
- /**
- * {@link SystemProperties} key that indicates if {@code qtaguid} bandwidth
- * controls have been enabled.
- */
- // TODO: remove when always enabled, or once socket tagging silently fails.
- public static final String PROP_QTAGUID_ENABLED = "net.qtaguid_enabled";
-
private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() {
@Override
protected SocketTags initialValue() {
@@ -88,13 +80,11 @@
private void tagSocketFd(FileDescriptor fd, int tag, int uid) {
if (tag == -1 && uid == -1) return;
- if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
- final int errno = native_tagSocketFd(fd, tag, uid);
- if (errno < 0) {
- Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", "
- + tag + ", " +
- + uid + ") failed with errno" + errno);
- }
+ final int errno = native_tagSocketFd(fd, tag, uid);
+ if (errno < 0) {
+ Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", "
+ + tag + ", "
+ + uid + ") failed with errno" + errno);
}
}
@@ -110,11 +100,9 @@
final SocketTags options = threadSocketTags.get();
if (options.statsTag == -1 && options.statsUid == -1) return;
- if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
- final int errno = native_untagSocketFd(fd);
- if (errno < 0) {
- Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno);
- }
+ final int errno = native_untagSocketFd(fd);
+ if (errno < 0) {
+ Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno);
}
}
@@ -124,21 +112,17 @@
}
public static void setKernelCounterSet(int uid, int counterSet) {
- if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
- final int errno = native_setCounterSet(counterSet, uid);
- if (errno < 0) {
- Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno "
- + errno);
- }
+ final int errno = native_setCounterSet(counterSet, uid);
+ if (errno < 0) {
+ Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno "
+ + errno);
}
}
public static void resetKernelUidStats(int uid) {
- if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
- int errno = native_deleteTagData(0, uid);
- if (errno < 0) {
- Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno);
- }
+ int errno = native_deleteTagData(0, uid);
+ if (errno < 0) {
+ Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno);
}
}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 97cac29..a131111 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -746,8 +746,9 @@
}
const bool checkJni = GetBoolProperty("dalvik.vm.checkjni", false);
- ALOGV("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) {
+ ALOGD("CheckJNI is ON");
+
/* extended JNI checking */
addOption("-Xcheck:jni");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8d12df22..e477183 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -889,6 +889,12 @@
return array;
}
+static jlong nativeGetPrimaryPhysicalDisplayId(JNIEnv* env, jclass clazz) {
+ PhysicalDisplayId displayId;
+ SurfaceComposerClient::getPrimaryPhysicalDisplayId(&displayId);
+ return static_cast<jlong>(displayId.value);
+}
+
static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
sp<IBinder> token =
SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(physicalDisplayId));
@@ -1879,6 +1885,8 @@
(void*)nativeReleaseFrameRateFlexibilityToken },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },
+ {"nativeGetPrimaryPhysicalDisplayId", "()J",
+ (void*)nativeGetPrimaryPhysicalDisplayId },
{"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
(void*)nativeGetPhysicalDisplayToken },
{"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index be82879..ef6fd7d 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -36,6 +36,7 @@
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <linux/fs.h>
#include <memory>
@@ -253,6 +254,16 @@
return INSTALL_FAILED_CONTAINER_ERROR;
}
+ // If a filesystem like f2fs supports per-file compression, set the compression bit before data
+ // writes
+ unsigned int flags;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
+ ALOGE("Failed to call FS_IOC_GETFLAGS on %s: %s\n", localTmpFileName, strerror(errno));
+ } else if ((flags & FS_COMPR_FL) == 0) {
+ flags |= FS_COMPR_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &flags);
+ }
+
if (!zipFile->uncompressEntry(zipEntry, fd)) {
ALOGE("Failed uncompressing %s to %s\n", fileName, localTmpFileName);
close(fd);
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index fa1e9d4..a62ddd0 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -351,6 +351,7 @@
optional bool translucent = 30;
optional bool pip_auto_enter_enabled = 31;
optional bool in_size_compat_mode = 32;
+ optional float min_aspect_ratio = 33;
}
/* represents WindowToken */
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a5f5051..dc92e10 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1984,6 +1984,22 @@
<enum name="KEYCODE_THUMBS_UP" value="286" />
<enum name="KEYCODE_THUMBS_DOWN" value="287" />
<enum name="KEYCODE_PROFILE_SWITCH" value="288" />
+ <enum name="KEYCODE_VIDEO_APP_1" value="289" />
+ <enum name="KEYCODE_VIDEO_APP_2" value="290" />
+ <enum name="KEYCODE_VIDEO_APP_3" value="291" />
+ <enum name="KEYCODE_VIDEO_APP_4" value="292" />
+ <enum name="KEYCODE_VIDEO_APP_5" value="293" />
+ <enum name="KEYCODE_VIDEO_APP_6" value="294" />
+ <enum name="KEYCODE_VIDEO_APP_7" value="295" />
+ <enum name="KEYCODE_VIDEO_APP_8" value="296" />
+ <enum name="KEYCODE_FEATURED_APP_1" value="297" />
+ <enum name="KEYCODE_FEATURED_APP_2" value="298" />
+ <enum name="KEYCODE_FEATURED_APP_3" value="299" />
+ <enum name="KEYCODE_FEATURED_APP_4" value="300" />
+ <enum name="KEYCODE_DEMO_APP_1" value="301" />
+ <enum name="KEYCODE_DEMO_APP_2" value="302" />
+ <enum name="KEYCODE_DEMO_APP_3" value="303" />
+ <enum name="KEYCODE_DEMO_APP_4" value="304" />
</attr>
<!-- ***************************************************************** -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a350d14..be5063f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -64,16 +64,74 @@
<!-- Displayed when a carrier does not support call forwarding queries when roaming. -->
<string name="mmiErrorWhileRoaming">Can not change call forwarding settings from your phone while you are roaming.</string>
- <!-- Displayed when a phone feature such as call barring was activated. -->
+ <!-- Displayed when a phone feature such as call forwarding, call waiting, or call barring was
+ activated.
+ Used to build messages of the form:
+ <X>
+ <Y>
+
+ Where <X> is the name of the service which was enabled. Can be one of:
+ {@link #BaMmi Call barring}, {@link #CfMmi Call forwarding},
+ {@link #PwdMmi Password change}, {@link #CwMmi Call waiting},
+ {@link #ClipMmi Incoming Caller ID}, {@link #ClirMmi Hide Outgoing Caller ID},
+ {@link #ColpMmi Connected Line ID}, {@link #ColrMmi Connected Line ID Restriction}.
+ And <Y> is {@link #serviceEnabled} (this string).
+ -->
<string name="serviceEnabled">Service was enabled.</string>
<!-- Displayed in front of the list of a set of service classes
- (voice, data, fax, etc.) that were enabled. -->
+ (voice, data, fax, etc.) that call waiting were enabled for.
+ Will be used with messages of the form:
+ <X>
+ <Y1>
+ ...
+ <Yn>
+ Where <X> is {@link #serviceEnabledFor} (this string) and <Y>..<Yn> can be:
+ {@link #serviceClassData}, {@link #serviceClassVoice}, {@link #serviceClassFAX},
+ {@link #serviceClassSMS}, {@link #serviceClassDataAsync}, {@link #serviceClassDataSync},
+ {@link #serviceClassPacket}, {@link #serviceClassPAD}.
+ -->
<string name="serviceEnabledFor">Service was enabled for:</string>
- <!-- Displayed when a phone feature such as call forwarding was deactivated. -->
+ <!-- Displayed when a phone feature such as call forwarding was deactivated.
+ Used to build messages of the form:
+ <X>
+ <Y>
+
+ Where <X> is the name of the service which was disabled. Can be one of:
+ {@link #BaMmi Call barring}, {@link #CfMmi Call forwarding},
+ {@link #PwdMmi Password change}, {@link #CwMmi Call waiting},
+ {@link #ClipMmi Incoming Caller ID}, {@link #ClirMmi Hide Outgoing Caller ID},
+ {@link #ColpMmi Connected Line ID}, {@link #ColrMmi Connected Line ID Restriction}.
+ And <Y> is {@link #serviceDisabled} (this string).
+ -->
<string name="serviceDisabled">Service has been disabled.</string>
- <!-- Displayed when a phone property such as a SIM password was registered. -->
+ <!-- Displayed when a phone property such as a SIM password was registered. Registration
+ entails setting up a service for use, where {@link #serviceEnabled} entails enabling a
+ previously registered service.
+ Used to build messages of the form:
+ <X>
+ <Y>
+
+ Where <X> is the name of the service which was registered. Can be one of:
+ {@link #BaMmi Call barring}, {@link #CfMmi Call forwarding},
+ {@link #PwdMmi Password change}, {@link #CwMmi Call waiting},
+ {@link #ClipMmi Incoming Caller ID}, {@link #ClirMmi Hide Outgoing Caller ID},
+ {@link #ColpMmi Connected Line ID}, {@link #ColrMmi Connected Line ID Restriction}.
+ And <Y> is {@link #serviceRegistered} (this string). -->
<string name="serviceRegistered">Registration was successful.</string>
- <!-- Displayed when a phone property such as a SIM password was erased. -->
+ <!-- Displayed when a phone property such as a SIM password was erased.
+ Erasure is the opposite of {@link #serviceRegistered} and entails removal of a service.
+
+ Used to build messages of the form:
+ <X>
+ <Y>
+
+ Where <X> is the name of the service which was registered. Can be one of:
+ {@link #BaMmi Call barring}, {@link #CfMmi Call forwarding},
+ {@link #PwdMmi Password change}, {@link #CwMmi Call waiting},
+ {@link #ClipMmi Incoming Caller ID}, {@link #ClirMmi Hide Outgoing Caller ID},
+ {@link #ColpMmi Connected Line ID}, {@link #ColrMmi Connected Line ID Restriction}.
+ And <Y> is {@link #serviceErased} (this string).
+ -->
<string name="serviceErased">Erasure was successful.</string>
<!-- Displayed when a SIM password was entered incorrectly. -->
<string name="passwordIncorrect">Incorrect password.</string>
@@ -107,23 +165,32 @@
[CHAR LIMIT=10] -->
<string name="meid">MEID</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling caller ID.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="ClipMmi">Incoming Caller ID</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling caller ID.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="ClirMmi">Hide Outgoing Caller ID</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="ColpMmi">Connected Line ID</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID restriction. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID restriction.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="ColrMmi">Connected Line ID Restriction</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling call forwarding. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling call forwarding.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="CfMmi">Call forwarding</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling call waiting. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling call waiting.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="CwMmi">Call waiting</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling call barring. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling call barring.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="BaMmi">Call barring</string>
- <!-- Displayed as the title for a success/failure report changing the SIM password. -->
+ <!-- Displayed as the title for a success/failure report changing the SIM password.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="PwdMmi">Password change</string>
- <!-- Displayed as the title for a success/failure report changing the SIM PIN. -->
+ <!-- Displayed as the title for a success/failure report changing the SIM PIN.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="PinMmi">PIN change</string>
<string name="CnipMmi">Calling number present</string>
<string name="CnirMmi">Calling number restricted</string>
@@ -198,21 +265,29 @@
<string name="peerTtyModeOff">Peer requested TTY Mode OFF</string>
<!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
- <!-- Example: Service was enabled for: Voice, Data -->
+ <!-- Example: Service was enabled for: Voice, Data
+ See {@link #serviceEnabledFor}.-->
<string name="serviceClassVoice">Voice</string>
- <!-- Example: Service was enabled for: Voice, Data -->
+ <!-- Example: Service was enabled for: Voice, Data.
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassData">Data</string>
- <!-- Example: Service was enabled for: Voice, FAX -->
+ <!-- Example: Service was enabled for: Voice, FAX
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassFAX">FAX</string>
- <!-- Example: Service was enabled for: Voice, SMS -->
+ <!-- Example: Service was enabled for: Voice, SMS
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassSMS">SMS</string>
- <!-- Meaning: asynchronous data. Example: Service was enabled for: Voice, Async -->
+ <!-- Meaning: asynchronous data. Example: Service was enabled for: Voice, Async
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassDataAsync">Async</string>
- <!-- Meaning: synchronous data. Example: Service was enabled for: Voice, Async -->
+ <!-- Meaning: synchronous data. Example: Service was enabled for: Voice, Async
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassDataSync">Sync</string>
- <!-- Meaning: packet data. Example: Service was enabled for: Voice, Packet -->
+ <!-- Meaning: packet data. Example: Service was enabled for: Voice, Packet
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassPacket">Packet</string>
- <!-- Meaning: unknown. Example: Service was enabled for: Voice, PAD -->
+ <!-- Meaning: unknown. Example: Service was enabled for: Voice, PAD
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassPAD">PAD</string>
<!-- CDMA Roaming Indicator Strings (non ERI)--> <skip />
diff --git a/core/tests/PlatformCompatFramework/OWNERS b/core/tests/PlatformCompatFramework/OWNERS
index cfd0a4b..ee3086a 100644
--- a/core/tests/PlatformCompatFramework/OWNERS
+++ b/core/tests/PlatformCompatFramework/OWNERS
@@ -1,6 +1 @@
-# Use this reviewer by default.
-platform-compat-eng+reviews@google.com
-
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+include tools/platform-compat:/OWNERS
diff --git a/core/tests/coretests/OWNERS b/core/tests/coretests/OWNERS
new file mode 100644
index 0000000..0fb0c30
--- /dev/null
+++ b/core/tests/coretests/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b67988e..c94b3d5 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -499,6 +499,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-1556507536": {
+ "message": "Passing transform hint %d for window %s%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-1554521902": {
"message": "showInsets(ime) was requested by different window: %s ",
"level": "WARN",
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index d80699d..f49e80a 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -1,3 +1,4 @@
# Bug component: 909476
# includes OWNERS from parent directories
natanieljr@google.com
+pablogamito@google.com
diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS
index 610fd80..17f5164 100644
--- a/libs/androidfw/OWNERS
+++ b/libs/androidfw/OWNERS
@@ -1,6 +1,6 @@
set noparent
toddke@google.com
-rtmitchell@google.com
+zyy@google.com
patb@google.com
per-file CursorWindow.cpp=omakoto@google.com
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index cf7039b..c7f5696 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -32,7 +32,6 @@
import android.app.PendingIntent;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -5796,112 +5795,25 @@
}
}
- /**
- * Indicate Hearing Aid connection state change and eventually suppress
- * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
- * This operation is asynchronous but its execution will still be sequentially scheduled
- * relative to calls to {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- * * BluetoothDevice, int, int, boolean, int)} and
- * and {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
- * @param device Bluetooth device connected/disconnected
- * @param state new connection state (BluetoothProfile.STATE_xxx)
- * @param musicDevice Default get system volume for the connecting device.
- * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or
- * {@link android.bluetooth.BluetoothProfile.HEARING_AID})
- * @param suppressNoisyIntent if true the
- * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
- * {@hide}
- */
- public void setBluetoothHearingAidDeviceConnectionState(
- BluetoothDevice device, int state, boolean suppressNoisyIntent,
- int musicDevice) {
- final IAudioService service = getService();
- try {
- service.setBluetoothHearingAidDeviceConnectionState(device,
- state, suppressNoisyIntent, musicDevice);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
/**
- * Indicate Le Audio output device connection state change and eventually suppress
- * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
- * @param device Bluetooth device connected/disconnected
- * @param state new connection state (BluetoothProfile.STATE_xxx)
- * @param suppressNoisyIntent if true the
- * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
- * {@hide}
- */
- public void setBluetoothLeAudioOutDeviceConnectionState(BluetoothDevice device, int state,
- boolean suppressNoisyIntent) {
- final IAudioService service = getService();
- try {
- service.setBluetoothLeAudioOutDeviceConnectionState(device, state, suppressNoisyIntent);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Indicate Le Audio input connection state change.
- * @param device Bluetooth device connected/disconnected
- * @param state new connection state (BluetoothProfile.STATE_xxx)
- * {@hide}
- */
- public void setBluetoothLeAudioInDeviceConnectionState(BluetoothDevice device, int state) {
- final IAudioService service = getService();
- try {
- service.setBluetoothLeAudioInDeviceConnectionState(device, state);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Indicate A2DP source or sink connection state change and eventually suppress
- * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
- * This operation is asynchronous but its execution will still be sequentially scheduled
- * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice,
- * int, boolean, int)} and
- * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
- * @param device Bluetooth device connected/disconnected
- * @param state new connection state, {@link BluetoothProfile#STATE_CONNECTED}
- * or {@link BluetoothProfile#STATE_DISCONNECTED}
- * @param profile profile for the A2DP device
- * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting.
- * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
- * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
- * @param suppressNoisyIntent if true the
- * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+ * Indicate Bluetooth profile connection state change.
+ * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
+ * <code>previousDevice</code>
+ * This operation is asynchronous.
+ *
+ * @param newDevice Bluetooth device connected or null if there is no new devices
+ * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
+ * devices
+ * @param info contain all info related to the device. {@link BtProfileConnectionInfo}
* {@hide}
*/
- public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- BluetoothDevice device, int state,
- int profile, boolean suppressNoisyIntent, int a2dpVolume) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
+ @Nullable BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) {
final IAudioService service = getService();
try {
- service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
- state, profile, suppressNoisyIntent, a2dpVolume);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Indicate A2DP device configuration has changed.
- * This operation is asynchronous but its execution will still be sequentially scheduled
- * relative to calls to
- * {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice, int, int,
- * boolean, int)} and
- * {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, int, boolean, int)}
- * @param device Bluetooth device whose configuration has changed.
- * {@hide}
- */
- public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) {
- final IAudioService service = getService();
- try {
- service.handleBluetoothA2dpDeviceConfigChange(device);
+ service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/BtProfileConnectionInfo.aidl b/media/java/android/media/BtProfileConnectionInfo.aidl
new file mode 100644
index 0000000..047f06b
--- /dev/null
+++ b/media/java/android/media/BtProfileConnectionInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable BtProfileConnectionInfo;
+
diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BtProfileConnectionInfo.java
new file mode 100644
index 0000000..19ea2de
--- /dev/null
+++ b/media/java/android/media/BtProfileConnectionInfo.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.bluetooth.BluetoothProfile;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Contains information about Bluetooth profile connection state changed
+ * {@hide}
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class BtProfileConnectionInfo implements Parcelable {
+ /** @hide */
+ @IntDef({
+ BluetoothProfile.A2DP,
+ BluetoothProfile.A2DP_SINK, // Can only be set by BtHelper
+ BluetoothProfile.HEADSET, // Can only be set by BtHelper
+ BluetoothProfile.HEARING_AID,
+ BluetoothProfile.LE_AUDIO,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BtProfile {}
+
+ private final @BtProfile int mProfile;
+ private final boolean mSupprNoisy;
+ private final int mVolume;
+ private final boolean mIsLeOutput;
+
+ private BtProfileConnectionInfo(@BtProfile int profile, boolean suppressNoisyIntent, int volume,
+ boolean isLeOutput) {
+ mProfile = profile;
+ mSupprNoisy = suppressNoisyIntent;
+ mVolume = volume;
+ mIsLeOutput = isLeOutput;
+ }
+
+ /**
+ * Constructor used by BtHelper when a profile is connected
+ * {@hide}
+ */
+ public BtProfileConnectionInfo(@BtProfile int profile) {
+ this(profile, false, -1, false);
+ }
+
+ public static final @NonNull Parcelable.Creator<BtProfileConnectionInfo> CREATOR =
+ new Parcelable.Creator<BtProfileConnectionInfo>() {
+ @Override
+ public BtProfileConnectionInfo createFromParcel(Parcel source) {
+ return new BtProfileConnectionInfo(source.readInt(), source.readBoolean(),
+ source.readInt(), source.readBoolean());
+ }
+
+ @Override
+ public BtProfileConnectionInfo[] newArray(int size) {
+ return new BtProfileConnectionInfo[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) {
+ dest.writeInt(mProfile);
+ dest.writeBoolean(mSupprNoisy);
+ dest.writeInt(mVolume);
+ dest.writeBoolean(mIsLeOutput);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Constructor for A2dp info
+ *
+ * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
+ * intent will not be sent.
+ *
+ * @param volume of device -1 to ignore value
+ */
+ public static @NonNull BtProfileConnectionInfo a2dpInfo(boolean suppressNoisyIntent,
+ int volume) {
+ return new BtProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent, volume,
+ false);
+ }
+
+ /**
+ * Constructor for hearing aid info
+ *
+ * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
+ * intent will not be sent.
+ */
+ public static @NonNull BtProfileConnectionInfo hearingAidInfo(boolean suppressNoisyIntent) {
+ return new BtProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent, -1,
+ false);
+ }
+
+ /**
+ * constructor for le audio info
+ *
+ * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
+ * intent will not be sent.
+ *
+ * @param isLeOutput if true mean the device is an output device, if false it's an input device
+ */
+ public static @NonNull BtProfileConnectionInfo leAudio(boolean suppressNoisyIntent,
+ boolean isLeOutput) {
+ return new BtProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent, -1,
+ isLeOutput);
+ }
+
+ /**
+ * @return The profile connection
+ */
+ public @BtProfile int getProfile() {
+ return mProfile;
+ }
+
+ /**
+ * @return {@code true} if {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be
+ * sent
+ */
+ public boolean getSuppressNoisyIntent() {
+ return mSupprNoisy;
+ }
+
+ /**
+ * Only for {@link BluetoothProfile.A2DP} profile
+ * @return the volume of the connection or -1 if the value is ignored
+ */
+ public int getVolume() {
+ return mVolume;
+ }
+
+ /**
+ * Only for {@link BluetoothProfile.LE_AUDIO} profile
+ * @return {@code true} is the LE device is an output device, {@code false} if it's an input
+ * device
+ */
+ public boolean getIsLeOutput() {
+ return mIsLeOutput;
+ }
+}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index dd44fdf..5ff56f9 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -24,6 +24,7 @@
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
+import android.media.BtProfileConnectionInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -207,8 +208,6 @@
void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller);
- void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
-
@UnsupportedAppUsage
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
@@ -268,16 +267,8 @@
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
- void setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
- int state, boolean suppressNoisyIntent, int musicDevice);
-
- void setBluetoothLeAudioOutDeviceConnectionState(in BluetoothDevice device, int state,
- boolean suppressNoisyIntent);
-
- void setBluetoothLeAudioInDeviceConnectionState(in BluetoothDevice device, int state);
-
- void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
- int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
+ void handleBluetoothActiveDeviceChanged(in BluetoothDevice newDevice,
+ in BluetoothDevice previousDevice, in BtProfileConnectionInfo info);
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 8b91536..de31a7f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -60,10 +60,10 @@
with {@link MediaExtractor}, {@link MediaSync}, {@link MediaMuxer}, {@link MediaCrypto},
{@link MediaDrm}, {@link Image}, {@link Surface}, and {@link AudioTrack}.)
<p>
- <center><object style="width: 540px; height: 205px;" type="image/svg+xml"
- data="../../../images/media/mediacodec_buffers.svg"><img
- src="../../../images/media/mediacodec_buffers.png" style="width: 540px; height: 205px"
- alt="MediaCodec buffer flow diagram"></object></center>
+ <center>
+ <img src="../../../images/media/mediacodec_buffers.svg" style="width: 540px; height: 205px"
+ alt="MediaCodec buffer flow diagram">
+ </center>
<p>
In broad terms, a codec processes input data to generate output data. It processes data
asynchronously and uses a set of input and output buffers. At a simplistic level, you request
@@ -268,10 +268,10 @@
Uninitialized, Configured and Error, whereas the Executing state conceptually progresses through
three sub-states: Flushed, Running and End-of-Stream.
<p>
- <center><object style="width: 516px; height: 353px;" type="image/svg+xml"
- data="../../../images/media/mediacodec_states.svg"><img
- src="../../../images/media/mediacodec_states.png" style="width: 519px; height: 356px"
- alt="MediaCodec state diagram"></object></center>
+ <center>
+ <img src="../../../images/media/mediacodec_states.svg" style="width: 519px; height: 356px"
+ alt="MediaCodec state diagram">
+ </center>
<p>
When you create a codec using one of the factory methods, the codec is in the Uninitialized
state. First, you need to configure it via {@link #configure configure(…)}, which brings
@@ -513,10 +513,10 @@
Similarly, upon an initial call to {@code start} the codec will move directly to the Running
sub-state and start passing available input buffers via the callback.
<p>
- <center><object style="width: 516px; height: 353px;" type="image/svg+xml"
- data="../../../images/media/mediacodec_async_states.svg"><img
- src="../../../images/media/mediacodec_async_states.png" style="width: 516px; height: 353px"
- alt="MediaCodec state diagram for asynchronous operation"></object></center>
+ <center>
+ <img src="../../../images/media/mediacodec_async_states.svg" style="width: 516px; height: 353px"
+ alt="MediaCodec state diagram for asynchronous operation">
+ </center>
<p>
MediaCodec is typically used like this in asynchronous mode:
<pre class=prettyprint>
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index ecd9cc1..39b560b 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -65,6 +65,7 @@
case HAL_PIXEL_FORMAT_Y8:
case HAL_PIXEL_FORMAT_Y16:
case HAL_PIXEL_FORMAT_RAW16:
+ case HAL_PIXEL_FORMAT_RAW12:
case HAL_PIXEL_FORMAT_RAW10:
case HAL_PIXEL_FORMAT_RAW_OPAQUE:
case HAL_PIXEL_FORMAT_BLOB:
diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp
index 923377c..f90796e 100644
--- a/media/native/midi/amidi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -325,8 +325,8 @@
}
uint8_t readBuffer[AMIDI_PACKET_SIZE];
- ssize_t readCount = read(mPort->ufd, readBuffer, sizeof(readBuffer));
- if (readCount == EINTR || readCount < 1) {
+ ssize_t readCount = TEMP_FAILURE_RETRY(read(mPort->ufd, readBuffer, sizeof(readBuffer)));
+ if (readCount < 1) {
return AMEDIA_ERROR_UNKNOWN;
}
@@ -407,7 +407,8 @@
ssize_t numTransferBytes =
AMIDI_makeSendBuffer(writeBuffer, data + numSent, blockSize, timestamp);
- ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, writeBuffer, numTransferBytes);
+ ssize_t numWritten = TEMP_FAILURE_RETRY(write(((AMIDI_Port*)inputPort)->ufd, writeBuffer,
+ numTransferBytes));
if (numWritten < 0) {
break; // error so bail out.
}
@@ -430,7 +431,8 @@
uint8_t opCode = AMIDI_OPCODE_FLUSH;
ssize_t numTransferBytes = 1;
- ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, &opCode, numTransferBytes);
+ ssize_t numWritten = TEMP_FAILURE_RETRY(write(((AMIDI_Port*)inputPort)->ufd, &opCode,
+ numTransferBytes));
if (numWritten < numTransferBytes) {
ALOGE("AMidiInputPort_flush Couldn't write MIDI flush. requested:%zd, written:%zd",
diff --git a/mms/OWNERS b/mms/OWNERS
index 7f05a2a..f56845e 100644
--- a/mms/OWNERS
+++ b/mms/OWNERS
@@ -3,16 +3,15 @@
tgunn@google.com
breadley@google.com
rgreenwalt@google.com
-amitmahajan@google.com
fionaxu@google.com
jackyu@google.com
jminjie@google.com
satk@google.com
shuoq@google.com
-nazaninb@google.com
sarahchin@google.com
xiaotonj@google.com
huiwang@google.com
jayachandranc@google.com
chinmayd@google.com
amruthr@google.com
+sasindran@google.com
diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS
index 0d23f05..b9de5a3 100644
--- a/packages/CarrierDefaultApp/OWNERS
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -2,17 +2,16 @@
tgunn@google.com
breadley@google.com
rgreenwalt@google.com
-amitmahajan@google.com
fionaxu@google.com
jackyu@google.com
jminjie@google.com
satk@google.com
shuoq@google.com
-nazaninb@google.com
sarahchin@google.com
xiaotonj@google.com
huiwang@google.com
jayachandranc@google.com
chinmayd@google.com
amruthr@google.com
+sasindran@google.com
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
index 5252c6c..52d243a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
@@ -20,9 +20,8 @@
import static org.robolectric.shadow.api.Shadow.extract;
-import android.net.ConnectivityManager;
import android.os.UserManager;
-import android.util.SparseBooleanArray;
+import android.telephony.TelephonyManager;
import org.junit.Before;
import org.junit.Test;
@@ -35,7 +34,7 @@
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {SimStatusImeiInfoPreferenceControllerTest.ShadowUserManager.class,
- SimStatusImeiInfoPreferenceControllerTest.ShadowConnectivityManager.class})
+ SimStatusImeiInfoPreferenceControllerTest.ShadowTelephonyManager.class})
public class SimStatusImeiInfoPreferenceControllerTest {
private AbstractSimStatusImeiInfoPreferenceController mController;
@@ -56,9 +55,9 @@
ShadowUserManager userManager =
extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
userManager.setIsAdminUser(true);
- ShadowConnectivityManager connectivityManager =
- extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class));
- connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true);
+ ShadowTelephonyManager telephonyManager =
+ extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class));
+ telephonyManager.setDataCapable(true);
assertThat(mController.isAvailable()).isTrue();
}
@@ -68,9 +67,9 @@
ShadowUserManager userManager =
extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
userManager.setIsAdminUser(true);
- ShadowConnectivityManager connectivityManager =
- extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class));
- connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
+ ShadowTelephonyManager telephonyManager =
+ extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class));
+ telephonyManager.setDataCapable(false);
assertThat(mController.isAvailable()).isFalse();
}
@@ -99,19 +98,17 @@
}
}
- @Implements(ConnectivityManager.class)
- public static class ShadowConnectivityManager
- extends org.robolectric.shadows.ShadowConnectivityManager {
-
- private final SparseBooleanArray mSupportedNetworkTypes = new SparseBooleanArray();
-
- private void setNetworkSupported(int networkType, boolean supported) {
- mSupportedNetworkTypes.put(networkType, supported);
+ @Implements(TelephonyManager.class)
+ public static class ShadowTelephonyManager
+ extends org.robolectric.shadows.ShadowTelephonyManager {
+ private boolean mDataCapable = false;
+ private void setDataCapable(boolean capable) {
+ mDataCapable = capable;
}
@Implementation
- public boolean isNetworkSupported(int networkType) {
- return mSupportedNetworkTypes.get(networkType);
+ public boolean isDataCapable() {
+ return mDataCapable;
}
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 54fb647..76b0b38 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -641,6 +641,15 @@
</intent-filter>
</receiver>
+ <receiver
+ android:name=".ProfcollectUploadReceiver"
+ android:exported="true"
+ android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD" >
+ <intent-filter>
+ <action android:name="com.android.shell.action.PROFCOLLECT_UPLOAD" />
+ </intent-filter>
+ </receiver>
+
<service
android:name=".BugreportProgressService"
android:exported="false"/>
diff --git a/packages/Shell/res/xml/file_provider_paths.xml b/packages/Shell/res/xml/file_provider_paths.xml
index 225c757..85d7dd3 100644
--- a/packages/Shell/res/xml/file_provider_paths.xml
+++ b/packages/Shell/res/xml/file_provider_paths.xml
@@ -1,3 +1,4 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="bugreports" path="bugreports/" />
+ <root-path name="profcollect" path="/data/misc/profcollectd/report/" />
</paths>
diff --git a/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java b/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java
new file mode 100644
index 0000000..d2da724
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.shell;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+
+import androidx.core.content.FileProvider;
+
+import com.android.internal.R;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * A proxy service that relays report upload requests to the uploader app, while translating
+ * the path to the report to a content URI owned by this service.
+ */
+public final class ProfcollectUploadReceiver extends BroadcastReceiver {
+ private static final String AUTHORITY = "com.android.shell";
+ private static final String PROFCOLLECT_DATA_ROOT = "/data/misc/profcollectd/report/";
+
+ private static final String LOG_TAG = "ProfcollectUploadReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(LOG_TAG, "Received upload intent");
+
+ String uploaderPkg = getUploaderPackageName(context);
+ String uploaderAction = getUploaderActionName(context);
+
+ try {
+ ApplicationInfo info = context.getPackageManager().getApplicationInfo(uploaderPkg,
+ 0);
+ if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Log.e(LOG_TAG, "The profcollect uploader app " + uploaderPkg
+ + " must be a system application");
+ return;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot find profcollect uploader app " + uploaderPkg);
+ return;
+ }
+
+ String filename = intent.getStringExtra("filename");
+ File reportFile = new File(PROFCOLLECT_DATA_ROOT + filename);
+ Uri reportUri = FileProvider.getUriForFile(context, AUTHORITY, reportFile);
+ Intent uploadIntent =
+ new Intent(uploaderAction)
+ .setPackage(uploaderPkg)
+ .putExtra("EXTRA_DESTINATION", "PROFCOLLECT")
+ .putExtra("EXTRA_PACKAGE_NAME", context.getPackageName())
+ .setData(reportUri)
+ .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+
+ List<ResolveInfo> receivers =
+ context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0);
+ if (receivers == null || receivers.isEmpty()) {
+ Log.e(LOG_TAG, "No one to receive upload intent, abort upload.");
+ return;
+ }
+
+ context.grantUriPermission(uploaderPkg, reportUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ context.sendBroadcast(uploadIntent);
+ }
+
+ private String getUploaderPackageName(Context context) {
+ return context.getResources().getString(
+ R.string.config_defaultProfcollectReportUploaderApp);
+ }
+
+ private String getUploaderActionName(Context context) {
+ return context.getResources().getString(
+ R.string.config_defaultProfcollectReportUploaderAction);
+ }
+}
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 1cf14f2..e1da744 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -11,6 +11,7 @@
awickham@google.com
beverlyt@google.com
brockman@google.com
+brycelee@google.com
ccassidy@google.com
cinek@google.com
cwren@google.com
@@ -22,6 +23,7 @@
hyunyoungs@google.com
jaggies@google.com
jamesoleary@google.com
+jbolinger@google.com
jdemeulenaere@google.com
jeffdq@google.com
jjaggi@google.com
@@ -70,4 +72,4 @@
hseog@google.com
#Android TV
-rgl@google.com
\ No newline at end of file
+rgl@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java
index 376368f..d80d9cc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java
@@ -21,12 +21,19 @@
import android.content.Context;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
/**
* Manages the layout for under-display fingerprint sensors (UDFPS). Ensures that UI elements
* do not overlap with
*/
public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {
+ private static final String TAG = "AuthBiometricUdfpsView";
+
@Nullable private UdfpsDialogMeasureAdapter mMeasureAdapter;
public AuthBiometricUdfpsView(Context context) {
@@ -51,4 +58,23 @@
? mMeasureAdapter.onMeasureInternal(width, height, layoutParams)
: layoutParams;
}
+
+ @Override
+ void onLayoutInternal() {
+ super.onLayoutInternal();
+
+ // Move the UDFPS icon and indicator text if necessary. This probably only needs to happen
+ // for devices where the UDFPS sensor is too low.
+ // TODO(b/201510778): Update this logic to support cases where the sensor or text overlap
+ // the button bar area.
+ final int bottomSpacerHeight = mMeasureAdapter.getBottomSpacerHeight();
+ Log.w(TAG, "bottomSpacerHeight: " + bottomSpacerHeight);
+ if (bottomSpacerHeight < 0) {
+ FrameLayout iconFrame = findViewById(R.id.biometric_icon_frame);
+ iconFrame.setTranslationY(-bottomSpacerHeight);
+
+ TextView indicator = findViewById(R.id.indicator);
+ indicator.setTranslationY(-bottomSpacerHeight);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
index 7ccfb86..6185e59 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
@@ -45,6 +45,7 @@
@NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
@Nullable private WindowManager mWindowManager;
+ private int mBottomSpacerHeight;
public UdfpsDialogMeasureAdapter(
@NonNull ViewGroup view, @NonNull FingerprintSensorPropertiesInternal sensorProps) {
@@ -74,6 +75,16 @@
}
}
+ /**
+ * @return the actual (and possibly negative) bottom spacer height. If negative, this indicates
+ * that the UDFPS sensor is too low. Our current xml and custom measurement logic is very hard
+ * too cleanly support this case. So, let's have the onLayout code translate the sensor location
+ * instead.
+ */
+ int getBottomSpacerHeight() {
+ return mBottomSpacerHeight;
+ }
+
@NonNull
private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height) {
// Get the height of the everything below the icon. Currently, that's the indicator and
@@ -86,7 +97,7 @@
final int dialogMargin = getDialogMarginPx();
final int displayHeight = getWindowBounds().height();
final Insets navbarInsets = getNavbarInsets();
- final int bottomSpacerHeight = calculateBottomSpacerHeightForPortrait(
+ mBottomSpacerHeight = calculateBottomSpacerHeightForPortrait(
mSensorProps, displayHeight, textIndicatorHeight, buttonBarHeight,
dialogMargin, navbarInsets.bottom);
@@ -122,9 +133,10 @@
MeasureSpec.EXACTLY));
} else if (child.getId() == R.id.space_below_icon) {
// Set the spacer height so the fingerprint icon is on the physical sensor area
+ final int clampedSpacerHeight = Math.max(mBottomSpacerHeight, 0);
child.measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(bottomSpacerHeight, MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(clampedSpacerHeight, MeasureSpec.EXACTLY));
} else {
child.measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 15f77ff..8a213ec 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -239,18 +239,20 @@
if (mGhbmView != null && surface == null) {
Log.e(TAG, "doIlluminate | surface must be non-null for GHBM");
}
- mHbmProvider.enableHbm(mHbmType, surface, () -> {
- if (mGhbmView != null) {
- mGhbmView.drawIlluminationDot(mSensorRect);
- }
- if (onIlluminatedRunnable != null) {
- // No framework API can reliably tell when a frame reaches the panel. A timeout
- // is the safest solution.
- postDelayed(onIlluminatedRunnable, mOnIlluminatedDelayMs);
- } else {
- Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null");
- }
- });
+ if (mHbmProvider != null) {
+ mHbmProvider.enableHbm(mHbmType, surface, () -> {
+ if (mGhbmView != null) {
+ mGhbmView.drawIlluminationDot(mSensorRect);
+ }
+ if (onIlluminatedRunnable != null) {
+ // No framework API can reliably tell when a frame reaches the panel. A timeout
+ // is the safest solution.
+ postDelayed(onIlluminatedRunnable, mOnIlluminatedDelayMs);
+ } else {
+ Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null");
+ }
+ });
+ }
}
@Override
@@ -263,6 +265,8 @@
mGhbmView.setGhbmIlluminationListener(null);
mGhbmView.setVisibility(View.INVISIBLE);
}
- mHbmProvider.disableHbm(null /* onHbmDisabled */);
+ if (mHbmProvider != null) {
+ mHbmProvider.disableHbm(null /* onHbmDisabled */);
+ }
}
}
diff --git a/rs/jni/Android.bp b/rs/jni/Android.bp
new file mode 100644
index 0000000..9a6fa8e
--- /dev/null
+++ b/rs/jni/Android.bp
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_library_shared {
+ name: "librs_jni",
+
+ srcs: ["android_renderscript_RenderScript.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "libandroid_runtime",
+ "libandroidfw",
+ "libRS",
+ "libcutils",
+ "libhwui",
+ "liblog",
+ "libutils",
+ "libui",
+ "libgui",
+ "libjnigraphics",
+ ],
+
+ header_libs: [
+ "jni_headers",
+ "libbase_headers",
+ ],
+
+ include_dirs: ["frameworks/rs"],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wunused",
+ "-Wunreachable-code",
+ "-Wno-deprecated-declarations",
+ ],
+}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
deleted file mode 100644
index 0caba42..0000000
--- a/rs/jni/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- android_renderscript_RenderScript.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid \
- libandroid_runtime \
- libandroidfw \
- libRS \
- libcutils \
- libhwui \
- liblog \
- libutils \
- libui \
- libgui \
- libjnigraphics
-
-LOCAL_HEADER_LIBRARIES := \
- jni_headers \
- libbase_headers
-
-LOCAL_C_INCLUDES += \
- frameworks/rs
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-deprecated-declarations
-
-LOCAL_MODULE:= librs_jni
-LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS:= notice
-LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 55b982b..2103bcc 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -138,9 +138,11 @@
"android.hardware.boot-V1.1-java",
"android.hardware.boot-V1.2-java",
"android.hardware.broadcastradio-V2.0-java",
- "android.hardware.health-V1.0-java",
- "android.hardware.health-V2.0-java",
- "android.hardware.health-V2.1-java",
+ "android.hardware.health-V1.0-java", // HIDL
+ "android.hardware.health-V2.0-java", // HIDL
+ "android.hardware.health-V2.1-java", // HIDL
+ "android.hardware.health-V1-java", // AIDL
+ "android.hardware.health-translate-java",
"android.hardware.light-V1-java",
"android.hardware.tv.cec-V1.1-java",
"android.hardware.weaver-V1.0-java",
@@ -149,7 +151,7 @@
"android.hardware.biometrics.fingerprint-V2.3-java",
"android.hardware.biometrics.fingerprint-V1-java",
"android.hardware.oemlock-V1.0-java",
- "android.hardware.configstore-V1.0-java",
+ "android.hardware.configstore-V1.1-java",
"android.hardware.contexthub-V1.0-java",
"android.hardware.rebootescrow-V1-java",
"android.hardware.soundtrigger-V2.3-java",
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 0146aa8..844ac86 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -17,6 +17,7 @@
package com.android.server;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import static com.android.server.health.Utils.copyV1Battery;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -25,14 +26,8 @@
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
-import android.hardware.health.V1_0.HealthInfo;
-import android.hardware.health.V2_0.IHealth;
-import android.hardware.health.V2_0.Result;
+import android.hardware.health.HealthInfo;
import android.hardware.health.V2_1.BatteryCapacityLevel;
-import android.hardware.health.V2_1.Constants;
-import android.hardware.health.V2_1.IHealthInfoCallback;
-import android.hidl.manager.V1_0.IServiceManager;
-import android.hidl.manager.V1_0.IServiceNotification;
import android.metrics.LogMaker;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
@@ -44,7 +39,6 @@
import android.os.DropBoxManager;
import android.os.FileUtils;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.OsProtoEnums;
@@ -62,15 +56,14 @@
import android.service.battery.BatteryServiceDumpProto;
import android.sysprop.PowerProperties;
import android.util.EventLog;
-import android.util.MutableInt;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.DumpUtils;
import com.android.server.am.BatteryStatsService;
+import com.android.server.health.HealthServiceWrapper;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
@@ -82,8 +75,6 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicReference;
/**
* <p>BatteryService monitors the charging status, and charge level of the device
@@ -147,7 +138,6 @@
private HealthInfo mHealthInfo;
private final HealthInfo mLastHealthInfo = new HealthInfo();
- private android.hardware.health.V2_1.HealthInfo mHealthInfo2p1;
private boolean mBatteryLevelCritical;
private int mLastBatteryStatus;
private int mLastBatteryHealth;
@@ -191,7 +181,6 @@
private ActivityManagerInternal mActivityManagerInternal;
private HealthServiceWrapper mHealthServiceWrapper;
- private HealthHalCallback mHealthHalCallback;
private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
private ArrayDeque<Bundle> mBatteryLevelsEventQueue;
private long mLastBatteryLevelChangedSentMs;
@@ -274,13 +263,9 @@
private void registerHealthCallback() {
traceBegin("HealthInitWrapper");
- mHealthServiceWrapper = new HealthServiceWrapper();
- mHealthHalCallback = new HealthHalCallback();
// IHealth is lazily retrieved.
try {
- mHealthServiceWrapper.init(mHealthHalCallback,
- new HealthServiceWrapper.IServiceManagerSupplier() {},
- new HealthServiceWrapper.IHealthSupplier() {});
+ mHealthServiceWrapper = HealthServiceWrapper.create(this::update);
} catch (RemoteException ex) {
Slog.e(TAG, "health: cannot register callback. (RemoteException)");
throw ex.rethrowFromSystemServer();
@@ -368,8 +353,8 @@
}
private boolean shouldShutdownLocked() {
- if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) {
- return (mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL);
+ if (mHealthInfo.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) {
+ return (mHealthInfo.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL);
}
if (mHealthInfo.batteryLevel > 0) {
return false;
@@ -411,7 +396,7 @@
// shut down gracefully if temperature is too high (> 68.0C by default)
// wait until the system has booted before attempting to display the
// shutdown dialog.
- if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) {
+ if (mHealthInfo.batteryTemperatureTenthsCelsius > mShutdownBatteryTemperature) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -428,51 +413,28 @@
}
}
- private void update(android.hardware.health.V2_1.HealthInfo info) {
+ private void update(android.hardware.health.HealthInfo info) {
traceBegin("HealthInfoUpdate");
- Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryChargeCounter",
- info.legacy.legacy.batteryChargeCounter);
- Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent",
- info.legacy.legacy.batteryCurrent);
- Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType",
- plugType(info.legacy.legacy));
- Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus",
- info.legacy.legacy.batteryStatus);
+ Trace.traceCounter(
+ Trace.TRACE_TAG_POWER, "BatteryChargeCounter", info.batteryChargeCounterUah);
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent", info.batteryCurrentMicroamps);
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType", plugType(info));
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus", info.batteryStatus);
synchronized (mLock) {
if (!mUpdatesStopped) {
- mHealthInfo = info.legacy.legacy;
- mHealthInfo2p1 = info;
+ mHealthInfo = info;
// Process the new values.
processValuesLocked(false);
mLock.notifyAll(); // for any waiters on new info
} else {
- copy(mLastHealthInfo, info.legacy.legacy);
+ copyV1Battery(mLastHealthInfo, info);
}
}
traceEnd();
}
- private static void copy(HealthInfo dst, HealthInfo src) {
- dst.chargerAcOnline = src.chargerAcOnline;
- dst.chargerUsbOnline = src.chargerUsbOnline;
- dst.chargerWirelessOnline = src.chargerWirelessOnline;
- dst.maxChargingCurrent = src.maxChargingCurrent;
- dst.maxChargingVoltage = src.maxChargingVoltage;
- dst.batteryStatus = src.batteryStatus;
- dst.batteryHealth = src.batteryHealth;
- dst.batteryPresent = src.batteryPresent;
- dst.batteryLevel = src.batteryLevel;
- dst.batteryVoltage = src.batteryVoltage;
- dst.batteryTemperature = src.batteryTemperature;
- dst.batteryCurrent = src.batteryCurrent;
- dst.batteryCycleCount = src.batteryCycleCount;
- dst.batteryFullCharge = src.batteryFullCharge;
- dst.batteryChargeCounter = src.batteryChargeCounter;
- dst.batteryTechnology = src.batteryTechnology;
- }
-
private static int plugType(HealthInfo healthInfo) {
if (healthInfo.chargerAcOnline) {
return BatteryManager.BATTERY_PLUGGED_AC;
@@ -503,11 +465,16 @@
// Let the battery stats keep track of the current level.
try {
- mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,
- mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,
- mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,
- mHealthInfo.batteryFullCharge,
- mHealthInfo2p1.batteryChargeTimeToFullNowSeconds);
+ mBatteryStats.setBatteryState(
+ mHealthInfo.batteryStatus,
+ mHealthInfo.batteryHealth,
+ mPlugType,
+ mHealthInfo.batteryLevel,
+ mHealthInfo.batteryTemperatureTenthsCelsius,
+ mHealthInfo.batteryVoltageMillivolts,
+ mHealthInfo.batteryChargeCounterUah,
+ mHealthInfo.batteryFullChargeUah,
+ mHealthInfo.batteryChargeTimeToFullNowSeconds);
} catch (RemoteException e) {
// Should never happen.
}
@@ -515,17 +482,18 @@
shutdownIfNoPowerLocked();
shutdownIfOverTempLocked();
- if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus ||
- mHealthInfo.batteryHealth != mLastBatteryHealth ||
- mHealthInfo.batteryPresent != mLastBatteryPresent ||
- mHealthInfo.batteryLevel != mLastBatteryLevel ||
- mPlugType != mLastPlugType ||
- mHealthInfo.batteryVoltage != mLastBatteryVoltage ||
- mHealthInfo.batteryTemperature != mLastBatteryTemperature ||
- mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent ||
- mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage ||
- mHealthInfo.batteryChargeCounter != mLastChargeCounter ||
- mInvalidCharger != mLastInvalidCharger)) {
+ if (force
+ || (mHealthInfo.batteryStatus != mLastBatteryStatus
+ || mHealthInfo.batteryHealth != mLastBatteryHealth
+ || mHealthInfo.batteryPresent != mLastBatteryPresent
+ || mHealthInfo.batteryLevel != mLastBatteryLevel
+ || mPlugType != mLastPlugType
+ || mHealthInfo.batteryVoltageMillivolts != mLastBatteryVoltage
+ || mHealthInfo.batteryTemperatureTenthsCelsius != mLastBatteryTemperature
+ || mHealthInfo.maxChargingCurrentMicroamps != mLastMaxChargingCurrent
+ || mHealthInfo.maxChargingVoltageMicrovolts != mLastMaxChargingVoltage
+ || mHealthInfo.batteryChargeCounterUah != mLastChargeCounter
+ || mInvalidCharger != mLastInvalidCharger)) {
if (mPlugType != mLastPlugType) {
if (mLastPlugType == BATTERY_PLUGGED_NONE) {
@@ -582,8 +550,11 @@
if (mHealthInfo.batteryLevel != mLastBatteryLevel) {
// Don't do this just from voltage or temperature changes, that is
// too noisy.
- EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
- mHealthInfo.batteryLevel, mHealthInfo.batteryVoltage, mHealthInfo.batteryTemperature);
+ EventLog.writeEvent(
+ EventLogTags.BATTERY_LEVEL,
+ mHealthInfo.batteryLevel,
+ mHealthInfo.batteryVoltageMillivolts,
+ mHealthInfo.batteryTemperatureTenthsCelsius);
}
if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
mPlugType == BATTERY_PLUGGED_NONE) {
@@ -689,11 +660,11 @@
mLastBatteryPresent = mHealthInfo.batteryPresent;
mLastBatteryLevel = mHealthInfo.batteryLevel;
mLastPlugType = mPlugType;
- mLastBatteryVoltage = mHealthInfo.batteryVoltage;
- mLastBatteryTemperature = mHealthInfo.batteryTemperature;
- mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent;
- mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage;
- mLastChargeCounter = mHealthInfo.batteryChargeCounter;
+ mLastBatteryVoltage = mHealthInfo.batteryVoltageMillivolts;
+ mLastBatteryTemperature = mHealthInfo.batteryTemperatureTenthsCelsius;
+ mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrentMicroamps;
+ mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltageMicrovolts;
+ mLastChargeCounter = mHealthInfo.batteryChargeCounterUah;
mLastBatteryLevelCritical = mBatteryLevelCritical;
mLastInvalidCharger = mInvalidCharger;
}
@@ -716,13 +687,17 @@
intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
- intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
- intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
+ intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts);
+ intent.putExtra(
+ BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius);
intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology);
intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
- intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
- intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
- intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
+ intent.putExtra(
+ BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrentMicroamps);
+ intent.putExtra(
+ BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE,
+ mHealthInfo.maxChargingVoltageMicrovolts);
+ intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah);
if (DEBUG) {
Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
+ ", info:" + mHealthInfo.toString());
@@ -742,9 +717,9 @@
event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);
event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType);
- event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
- event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
- event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
+ event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts);
+ event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius);
+ event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah);
event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now);
boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty();
@@ -936,7 +911,7 @@
}
try {
if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
+ copyV1Battery(mLastHealthInfo, mHealthInfo);
}
boolean update = true;
switch (key) {
@@ -959,10 +934,10 @@
mHealthInfo.batteryLevel = Integer.parseInt(value);
break;
case "counter":
- mHealthInfo.batteryChargeCounter = Integer.parseInt(value);
+ mHealthInfo.batteryChargeCounterUah = Integer.parseInt(value);
break;
case "temp":
- mHealthInfo.batteryTemperature = Integer.parseInt(value);
+ mHealthInfo.batteryTemperatureTenthsCelsius = Integer.parseInt(value);
break;
case "invalid":
mInvalidCharger = Integer.parseInt(value);
@@ -1006,7 +981,7 @@
private void setChargerAcOnline(boolean online, boolean forceUpdate) {
if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
+ copyV1Battery(mLastHealthInfo, mHealthInfo);
}
mHealthInfo.chargerAcOnline = online;
mUpdatesStopped = true;
@@ -1015,7 +990,7 @@
private void setBatteryLevel(int level, boolean forceUpdate) {
if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
+ copyV1Battery(mLastHealthInfo, mHealthInfo);
}
mHealthInfo.batteryLevel = level;
mUpdatesStopped = true;
@@ -1024,7 +999,7 @@
private void unplugBattery(boolean forceUpdate, PrintWriter pw) {
if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
+ copyV1Battery(mLastHealthInfo, mHealthInfo);
}
mHealthInfo.chargerAcOnline = false;
mHealthInfo.chargerUsbOnline = false;
@@ -1036,7 +1011,7 @@
private void resetBattery(boolean forceUpdate, @Nullable PrintWriter pw) {
if (mUpdatesStopped) {
mUpdatesStopped = false;
- copy(mHealthInfo, mLastHealthInfo);
+ copyV1Battery(mHealthInfo, mLastHealthInfo);
Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw));
}
if (mBatteryInputSuspended) {
@@ -1071,16 +1046,16 @@
pw.println(" AC powered: " + mHealthInfo.chargerAcOnline);
pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline);
pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline);
- pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrent);
- pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltage);
- pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounter);
+ pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrentMicroamps);
+ pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltageMicrovolts);
+ pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounterUah);
pw.println(" status: " + mHealthInfo.batteryStatus);
pw.println(" health: " + mHealthInfo.batteryHealth);
pw.println(" present: " + mHealthInfo.batteryPresent);
pw.println(" level: " + mHealthInfo.batteryLevel);
pw.println(" scale: " + BATTERY_SCALE);
- pw.println(" voltage: " + mHealthInfo.batteryVoltage);
- pw.println(" temperature: " + mHealthInfo.batteryTemperature);
+ pw.println(" voltage: " + mHealthInfo.batteryVoltageMillivolts);
+ pw.println(" temperature: " + mHealthInfo.batteryTemperatureTenthsCelsius);
pw.println(" technology: " + mHealthInfo.batteryTechnology);
} else {
Shell shell = new Shell();
@@ -1103,16 +1078,23 @@
batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS;
}
proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
- proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
- proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
- proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
+ proto.write(
+ BatteryServiceDumpProto.MAX_CHARGING_CURRENT,
+ mHealthInfo.maxChargingCurrentMicroamps);
+ proto.write(
+ BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE,
+ mHealthInfo.maxChargingVoltageMicrovolts);
+ proto.write(
+ BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah);
proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus);
proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth);
proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent);
proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel);
proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
- proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltage);
- proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.batteryTemperature);
+ proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltageMillivolts);
+ proto.write(
+ BatteryServiceDumpProto.TEMPERATURE,
+ mHealthInfo.batteryTemperatureTenthsCelsius);
proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology);
}
proto.flush();
@@ -1184,64 +1166,6 @@
}
}
- private final class HealthHalCallback extends IHealthInfoCallback.Stub
- implements HealthServiceWrapper.Callback {
- @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
- android.hardware.health.V2_1.HealthInfo propsLatest =
- new android.hardware.health.V2_1.HealthInfo();
- propsLatest.legacy = props;
-
- propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED;
- propsLatest.batteryChargeTimeToFullNowSeconds =
- Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
-
- BatteryService.this.update(propsLatest);
- }
-
- @Override public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) {
- BatteryService.this.update(props);
- }
-
- // on new service registered
- @Override public void onRegistration(IHealth oldService, IHealth newService,
- String instance) {
- if (newService == null) return;
-
- traceBegin("HealthUnregisterCallback");
- try {
- if (oldService != null) {
- int r = oldService.unregisterCallback(this);
- if (r != Result.SUCCESS) {
- Slog.w(TAG, "health: cannot unregister previous callback: " +
- Result.toString(r));
- }
- }
- } catch (RemoteException ex) {
- Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
- + ex.getMessage());
- } finally {
- traceEnd();
- }
-
- traceBegin("HealthRegisterCallback");
- try {
- int r = newService.registerCallback(this);
- if (r != Result.SUCCESS) {
- Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
- return;
- }
- // registerCallback does NOT guarantee that update is called
- // immediately, so request a manual update here.
- newService.update();
- } catch (RemoteException ex) {
- Slog.e(TAG, "health: cannot register callback (transaction error): "
- + ex.getMessage());
- } finally {
- traceEnd();
- }
- }
- }
-
private final class BinderService extends Binder {
@Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -1265,71 +1189,11 @@
private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub {
@Override
public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
- traceBegin("HealthGetProperty");
- try {
- IHealth service = mHealthServiceWrapper.getLastService();
- if (service == null) throw new RemoteException("no health service");
- final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
- switch(id) {
- case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
- service.getChargeCounter((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
- service.getCurrentNow((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
- service.getCurrentAverage((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CAPACITY:
- service.getCapacity((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_STATUS:
- service.getChargeStatus((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
- service.getEnergyCounter((int result, long value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- }
- return outResult.value;
- } finally {
- traceEnd();
- }
+ return mHealthServiceWrapper.getProperty(id, prop);
}
@Override
public void scheduleUpdate() throws RemoteException {
- mHealthServiceWrapper.getHandlerThread().getThreadHandler().post(() -> {
- traceBegin("HealthScheduleUpdate");
- try {
- IHealth service = mHealthServiceWrapper.getLastService();
- if (service == null) {
- Slog.e(TAG, "no health service");
- return;
- }
- service.update();
- } catch (RemoteException ex) {
- Slog.e(TAG, "Cannot call update on health HAL", ex);
- } finally {
- traceEnd();
- }
- });
+ mHealthServiceWrapper.scheduleUpdate();
}
}
@@ -1358,14 +1222,14 @@
@Override
public int getBatteryChargeCounter() {
synchronized (mLock) {
- return mHealthInfo.batteryChargeCounter;
+ return mHealthInfo.batteryChargeCounterUah;
}
}
@Override
public int getBatteryFullCharge() {
synchronized (mLock) {
- return mHealthInfo.batteryFullCharge;
+ return mHealthInfo.batteryFullChargeUah;
}
}
@@ -1418,184 +1282,4 @@
BatteryService.this.suspendBatteryInput();
}
}
-
- /**
- * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when
- * necessary.
- *
- * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and
- * the internal service is refreshed.
- * On death of an existing IHealth service, the internal service is NOT cleared to avoid
- * race condition between death notification and new service notification. Hence,
- * a caller must check for transaction errors when calling into the service.
- *
- * @hide Should only be used internally.
- */
- public static final class HealthServiceWrapper {
- private static final String TAG = "HealthServiceWrapper";
- public static final String INSTANCE_VENDOR = "default";
-
- private final IServiceNotification mNotification = new Notification();
- private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder");
- // These variables are fixed after init.
- private Callback mCallback;
- private IHealthSupplier mHealthSupplier;
- private String mInstanceName;
-
- // Last IHealth service received.
- private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
-
- /**
- * init should be called after constructor. For testing purposes, init is not called by
- * constructor.
- */
- public HealthServiceWrapper() {
- }
-
- public IHealth getLastService() {
- return mLastService.get();
- }
-
- /**
- * See {@link #init(Callback, IServiceManagerSupplier, IHealthSupplier)}
- */
- public void init() throws RemoteException, NoSuchElementException {
- init(/* callback= */null, new HealthServiceWrapper.IServiceManagerSupplier() {},
- new HealthServiceWrapper.IHealthSupplier() {});
- }
-
- /**
- * Start monitoring registration of new IHealth services. Only instance
- * {@link #INSTANCE_VENDOR} and in device / framework manifest are used. This function should
- * only be called once.
- *
- * mCallback.onRegistration() is called synchronously (aka in init thread) before
- * this method returns if callback is not null.
- *
- * @throws RemoteException transaction error when talking to IServiceManager
- * @throws NoSuchElementException if one of the following cases:
- * - No service manager;
- * - {@link #INSTANCE_VENDOR} is not in manifests (i.e. not
- * available on this device), or none of these instances are available to current
- * process.
- * @throws NullPointerException when supplier is null
- */
- void init(@Nullable Callback callback,
- IServiceManagerSupplier managerSupplier,
- IHealthSupplier healthSupplier)
- throws RemoteException, NoSuchElementException, NullPointerException {
- if (managerSupplier == null || healthSupplier == null) {
- throw new NullPointerException();
- }
- IServiceManager manager;
-
- mHealthSupplier = healthSupplier;
-
- // Initialize mLastService and call callback for the first time (in init thread)
- IHealth newService = null;
- traceBegin("HealthInitGetService_" + INSTANCE_VENDOR);
- try {
- newService = healthSupplier.get(INSTANCE_VENDOR);
- } catch (NoSuchElementException ex) {
- /* ignored, handled below */
- } finally {
- traceEnd();
- }
- if (newService != null) {
- mInstanceName = INSTANCE_VENDOR;
- mLastService.set(newService);
- }
-
- if (mInstanceName == null || newService == null) {
- throw new NoSuchElementException(String.format(
- "IHealth service instance %s isn't available. Perhaps no permission?",
- INSTANCE_VENDOR));
- }
-
- if (callback != null) {
- mCallback = callback;
- mCallback.onRegistration(null, newService, mInstanceName);
- }
-
- // Register for future service registrations
- traceBegin("HealthInitRegisterNotification");
- mHandlerThread.start();
- try {
- managerSupplier.get().registerForNotifications(
- IHealth.kInterfaceName, mInstanceName, mNotification);
- } finally {
- traceEnd();
- }
- Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
- }
-
- @VisibleForTesting
- HandlerThread getHandlerThread() {
- return mHandlerThread;
- }
-
- interface Callback {
- /**
- * This function is invoked asynchronously when a new and related IServiceNotification
- * is received.
- * @param service the recently retrieved service from IServiceManager.
- * Can be a dead service before service notification of a new service is delivered.
- * Implementation must handle cases for {@link RemoteException}s when calling
- * into service.
- * @param instance instance name.
- */
- void onRegistration(IHealth oldService, IHealth newService, String instance);
- }
-
- /**
- * Supplier of services.
- * Must not return null; throw {@link NoSuchElementException} if a service is not available.
- */
- interface IServiceManagerSupplier {
- default IServiceManager get() throws NoSuchElementException, RemoteException {
- return IServiceManager.getService();
- }
- }
- /**
- * Supplier of services.
- * Must not return null; throw {@link NoSuchElementException} if a service is not available.
- */
- interface IHealthSupplier {
- default IHealth get(String name) throws NoSuchElementException, RemoteException {
- return IHealth.getService(name, true /* retry */);
- }
- }
-
- private class Notification extends IServiceNotification.Stub {
- @Override
- public final void onRegistration(String interfaceName, String instanceName,
- boolean preexisting) {
- if (!IHealth.kInterfaceName.equals(interfaceName)) return;
- if (!mInstanceName.equals(instanceName)) return;
-
- // This runnable only runs on mHandlerThread and ordering is ensured, hence
- // no locking is needed inside the runnable.
- mHandlerThread.getThreadHandler().post(new Runnable() {
- @Override
- public void run() {
- try {
- IHealth newService = mHealthSupplier.get(mInstanceName);
- IHealth oldService = mLastService.getAndSet(newService);
-
- // preexisting may be inaccurate (race). Check for equality here.
- if (Objects.equals(newService, oldService)) return;
-
- Slog.i(TAG, "health: new instance registered " + mInstanceName);
- // #init() may be called with null callback. Skip null callbacks.
- if (mCallback == null) return;
- mCallback.onRegistration(oldService, newService, mInstanceName);
- } catch (NoSuchElementException | RemoteException ex) {
- Slog.e(TAG, "health: Cannot get instance '" + mInstanceName
- + "': " + ex.getMessage() + ". Perhaps no permission?");
- }
- }
- });
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index c7e9068..a2c2dbd 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -39,8 +39,6 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.TrafficStats.UID_TETHERING;
-import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
-
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.Context;
@@ -72,7 +70,6 @@
import android.os.ServiceSpecificException;
import android.os.StrictMode;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.Trace;
import android.text.TextUtils;
import android.util.Log;
@@ -446,9 +443,6 @@
// push any existing quota or UID rules
synchronized (mQuotaLock) {
- // Netd unconditionally enable bandwidth control
- SystemProperties.set(PROP_QTAGUID_ENABLED, "1");
-
mStrictEnabled = true;
setDataSaverModeEnabled(mDataSaverMode);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c742708..5ed6c86 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -47,6 +47,7 @@
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telecom.TelecomManager;
+import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SrvccState;
@@ -1960,42 +1961,8 @@
ApnSetting apnSetting = preciseState.getApnSetting();
- int apnTypes = apnSetting.getApnTypeBitmask();
- int state = preciseState.getState();
- int networkType = preciseState.getNetworkType();
-
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
- // We only call the callback when the change is for default APN type.
- if ((ApnSetting.TYPE_DEFAULT & apnTypes) != 0
- && (mDataConnectionState[phoneId] != state
- || mDataConnectionNetworkType[phoneId] != networkType)) {
- String str = "onDataConnectionStateChanged("
- + TelephonyUtils.dataStateToString(state)
- + ", " + getNetworkTypeName(networkType)
- + ") subId=" + subId + ", phoneId=" + phoneId;
- log(str);
- mLocalLog.log(str);
- for (Record r : mRecords) {
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)
- && idMatch(r, subId, phoneId)) {
- try {
- if (DBG) {
- log("Notify data connection state changed on sub: " + subId);
- }
- r.callback.onDataConnectionStateChanged(state, networkType);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
- handleRemoveListLocked();
-
- mDataConnectionState[phoneId] = state;
- mDataConnectionNetworkType[phoneId] = networkType;
- }
-
Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
preciseState.getApnSetting());
PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
@@ -2027,6 +1994,73 @@
if (preciseState.getState() != TelephonyManager.DATA_DISCONNECTED) {
mPreciseDataConnectionStates.get(phoneId).put(key, preciseState);
}
+
+ // Note that below is just the workaround for reporting the correct data connection
+ // state. The actual fix should be put in the new data stack in T.
+ // TODO: Remove the code below in T.
+
+ // Collect all possible candidate data connection state for internet. Key is the
+ // data connection state, value is the precise data connection state.
+ Map<Integer, PreciseDataConnectionState> internetConnections = new ArrayMap<>();
+ if (preciseState.getState() == TelephonyManager.DATA_DISCONNECTED
+ && preciseState.getApnSetting().getApnTypes()
+ .contains(ApnSetting.TYPE_DEFAULT)) {
+ internetConnections.put(TelephonyManager.DATA_DISCONNECTED, preciseState);
+ }
+ for (Map.Entry<Pair<Integer, ApnSetting>, PreciseDataConnectionState> entry :
+ mPreciseDataConnectionStates.get(phoneId).entrySet()) {
+ if (entry.getKey().first == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
+ && entry.getKey().second.getApnTypes()
+ .contains(ApnSetting.TYPE_DEFAULT)) {
+ internetConnections.put(entry.getValue().getState(), entry.getValue());
+ }
+ }
+
+ // If any internet data is in connected state, then report connected, then check
+ // suspended, connecting, disconnecting, and disconnected. The order is very
+ // important.
+ int[] statesInPriority = new int[]{TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.DATA_SUSPENDED, TelephonyManager.DATA_CONNECTING,
+ TelephonyManager.DATA_DISCONNECTING,
+ TelephonyManager.DATA_DISCONNECTED};
+ int state = TelephonyManager.DATA_DISCONNECTED;
+ int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ for (int s : statesInPriority) {
+ if (internetConnections.containsKey(s)) {
+ state = s;
+ networkType = internetConnections.get(s).getNetworkType();
+ break;
+ }
+ }
+
+ if (mDataConnectionState[phoneId] != state
+ || mDataConnectionNetworkType[phoneId] != networkType) {
+ String str = "onDataConnectionStateChanged("
+ + TelephonyUtils.dataStateToString(state)
+ + ", " + TelephonyManager.getNetworkTypeName(networkType)
+ + ") subId=" + subId + ", phoneId=" + phoneId;
+ log(str);
+ mLocalLog.log(str);
+ for (Record r : mRecords) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)
+ && idMatch(r, subId, phoneId)) {
+ try {
+ if (DBG) {
+ log("Notify data connection state changed on sub: " + subId);
+ }
+ r.callback.onDataConnectionStateChanged(state, networkType);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+
+ mDataConnectionState[phoneId] = state;
+ mDataConnectionNetworkType[phoneId] = networkType;
+
+ handleRemoveListLocked();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 3ccacd8..c5ac390 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -94,6 +94,8 @@
DeviceConfig.NAMESPACE_STATSD_NATIVE,
DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT,
DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ DeviceConfig.NAMESPACE_TETHERING,
+ DeviceConfig.NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE,
DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
};
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index c383f51..0b2311b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -17,12 +17,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothLeAudio;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -32,6 +29,7 @@
import android.media.AudioManager;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
+import android.media.BtProfileConnectionInfo;
import android.media.IAudioRoutesObserver;
import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher;
@@ -516,29 +514,82 @@
}
};
- /*package*/ static final class BtDeviceConnectionInfo {
- final @NonNull BluetoothDevice mDevice;
- final @AudioService.BtProfileConnectionState int mState;
- final int mProfile;
- final boolean mSupprNoisy;
- final int mVolume;
+ /*package*/ static final class BtDeviceChangedData {
+ final @Nullable BluetoothDevice mNewDevice;
+ final @Nullable BluetoothDevice mPreviousDevice;
+ final @NonNull BtProfileConnectionInfo mInfo;
+ final @NonNull String mEventSource;
- BtDeviceConnectionInfo(@NonNull BluetoothDevice device,
- @AudioService.BtProfileConnectionState int state,
- int profile, boolean suppressNoisyIntent, int vol) {
- mDevice = device;
- mState = state;
- mProfile = profile;
- mSupprNoisy = suppressNoisyIntent;
- mVolume = vol;
+ BtDeviceChangedData(@Nullable BluetoothDevice newDevice,
+ @Nullable BluetoothDevice previousDevice,
+ @NonNull BtProfileConnectionInfo info, @NonNull String eventSource) {
+ mNewDevice = newDevice;
+ mPreviousDevice = previousDevice;
+ mInfo = info;
+ mEventSource = eventSource;
}
- BtDeviceConnectionInfo(@NonNull BtDeviceConnectionInfo info) {
- mDevice = info.mDevice;
- mState = info.mState;
- mProfile = info.mProfile;
- mSupprNoisy = info.mSupprNoisy;
- mVolume = info.mVolume;
+ @Override
+ public String toString() {
+ return "BtDeviceChangedData profile=" + BluetoothProfile.getProfileName(
+ mInfo.getProfile())
+ + ", switch device: [" + mPreviousDevice + "] -> [" + mNewDevice + "]";
+ }
+ }
+
+ /*package*/ static final class BtDeviceInfo {
+ final @NonNull BluetoothDevice mDevice;
+ final @AudioService.BtProfileConnectionState int mState;
+ final @AudioService.BtProfile int mProfile;
+ final boolean mSupprNoisy;
+ final int mVolume;
+ final boolean mIsLeOutput;
+ final @NonNull String mEventSource;
+ final @AudioSystem.AudioFormatNativeEnumForBtCodec int mCodec;
+ final int mAudioSystemDevice;
+ final int mMusicDevice;
+
+ BtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state,
+ int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) {
+ mDevice = device;
+ mState = state;
+ mProfile = d.mInfo.getProfile();
+ mSupprNoisy = d.mInfo.getSuppressNoisyIntent();
+ mVolume = d.mInfo.getVolume();
+ mIsLeOutput = d.mInfo.getIsLeOutput();
+ mEventSource = d.mEventSource;
+ mAudioSystemDevice = audioDevice;
+ mMusicDevice = AudioSystem.DEVICE_NONE;
+ mCodec = codec;
+ }
+
+ // constructor used by AudioDeviceBroker to search similar message
+ BtDeviceInfo(@NonNull BluetoothDevice device, int profile) {
+ mDevice = device;
+ mProfile = profile;
+ mEventSource = "";
+ mMusicDevice = AudioSystem.DEVICE_NONE;
+ mCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mAudioSystemDevice = 0;
+ mState = 0;
+ mSupprNoisy = false;
+ mVolume = -1;
+ mIsLeOutput = false;
+ }
+
+ // constructor used by AudioDeviceInventory when config change failed
+ BtDeviceInfo(@NonNull BluetoothDevice device, int profile, int state, int musicDevice,
+ int audioSystemDevice) {
+ mDevice = device;
+ mProfile = profile;
+ mEventSource = "";
+ mMusicDevice = musicDevice;
+ mCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mAudioSystemDevice = audioSystemDevice;
+ mState = state;
+ mSupprNoisy = false;
+ mVolume = -1;
+ mIsLeOutput = false;
}
// redefine equality op so we can match messages intended for this device
@@ -550,16 +601,52 @@
if (this == o) {
return true;
}
- if (o instanceof BtDeviceConnectionInfo) {
- return mDevice.equals(((BtDeviceConnectionInfo) o).mDevice);
+ if (o instanceof BtDeviceInfo) {
+ return mProfile == ((BtDeviceInfo) o).mProfile
+ && mDevice.equals(((BtDeviceInfo) o).mDevice);
}
return false;
}
+ }
- @Override
- public String toString() {
- return "BtDeviceConnectionInfo dev=" + mDevice.toString();
+ BtDeviceInfo createBtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device,
+ int state) {
+ int audioDevice;
+ int codec = AudioSystem.AUDIO_FORMAT_DEFAULT;
+ switch (d.mInfo.getProfile()) {
+ case BluetoothProfile.A2DP_SINK:
+ audioDevice = AudioSystem.DEVICE_IN_BLUETOOTH_A2DP;
+ break;
+ case BluetoothProfile.A2DP:
+ audioDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
+ synchronized (mDeviceStateLock) {
+ codec = mBtHelper.getA2dpCodec(device);
+ }
+ break;
+ case BluetoothProfile.HEARING_AID:
+ audioDevice = AudioSystem.DEVICE_OUT_HEARING_AID;
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ if (d.mInfo.getIsLeOutput()) {
+ audioDevice = AudioSystem.DEVICE_OUT_BLE_HEADSET;
+ } else {
+ audioDevice = AudioSystem.DEVICE_IN_BLE_HEADSET;
+ }
+ break;
+ default: throw new IllegalArgumentException("Invalid profile " + d.mInfo.getProfile());
}
+ return new BtDeviceInfo(d, device, state, audioDevice, codec);
+ }
+
+ private void btMediaMetricRecord(@NonNull BluetoothDevice device, String state,
+ @NonNull BtDeviceChangedData data) {
+ final String name = TextUtils.emptyIfNull(device.getName());
+ new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
+ + "queueOnBluetoothActiveDeviceChanged")
+ .set(MediaMetrics.Property.STATE, state)
+ .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
+ .set(MediaMetrics.Property.NAME, name)
+ .record();
}
/**
@@ -567,116 +654,37 @@
* not just a simple message post
* @param info struct with the (dis)connection information
*/
- /*package*/ void queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- @NonNull BtDeviceConnectionInfo info) {
- final String name = TextUtils.emptyIfNull(info.mDevice.getName());
- new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
- + "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent")
- .set(MediaMetrics.Property.STATE, info.mState == BluetoothProfile.STATE_CONNECTED
- ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
- .set(MediaMetrics.Property.INDEX, info.mVolume)
- .set(MediaMetrics.Property.NAME, name)
- .record();
-
- // operations of removing and posting messages related to A2DP device state change must be
- // mutually exclusive
- synchronized (mDeviceStateLock) {
- // when receiving a request to change the connection state of a device, this last
- // request is the source of truth, so cancel all previous requests that are already in
- // the handler
- removeScheduledA2dpEvents(info.mDevice);
-
- sendLMsgNoDelay(
- info.mState == BluetoothProfile.STATE_CONNECTED
- ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION
- : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
- SENDMSG_QUEUE, info);
+ /*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) {
+ if (data.mInfo.getProfile() == BluetoothProfile.A2DP && data.mPreviousDevice != null
+ && data.mPreviousDevice.equals(data.mNewDevice)) {
+ final String name = TextUtils.emptyIfNull(data.mNewDevice.getName());
+ new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
+ + "queueOnBluetoothActiveDeviceChanged_update")
+ .set(MediaMetrics.Property.NAME, name)
+ .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
+ .record();
+ synchronized (mDeviceStateLock) {
+ postBluetoothA2dpDeviceConfigChange(data.mNewDevice);
+ }
+ } else {
+ synchronized (mDeviceStateLock) {
+ if (data.mPreviousDevice != null) {
+ btMediaMetricRecord(data.mPreviousDevice, MediaMetrics.Value.DISCONNECTED,
+ data);
+ sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE,
+ createBtDeviceInfo(data, data.mPreviousDevice,
+ BluetoothProfile.STATE_DISCONNECTED));
+ }
+ if (data.mNewDevice != null) {
+ btMediaMetricRecord(data.mNewDevice, MediaMetrics.Value.CONNECTED, data);
+ sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE,
+ createBtDeviceInfo(data, data.mNewDevice,
+ BluetoothProfile.STATE_CONNECTED));
+ }
+ }
}
}
- /** remove all previously scheduled connection and state change events for the given device */
- @GuardedBy("mDeviceStateLock")
- private void removeScheduledA2dpEvents(@NonNull BluetoothDevice device) {
- mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, device);
-
- final BtDeviceConnectionInfo connectionInfoToRemove = new BtDeviceConnectionInfo(device,
- // the next parameters of the constructor will be ignored when finding the message
- // to remove as the equality of the message's object is tested on the device itself
- // (see BtDeviceConnectionInfo.equals() method override)
- BluetoothProfile.STATE_CONNECTED, 0, false, -1);
- mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
- connectionInfoToRemove);
- mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION,
- connectionInfoToRemove);
-
- final BtHelper.BluetoothA2dpDeviceInfo devInfoToRemove =
- new BtHelper.BluetoothA2dpDeviceInfo(device);
- mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
- devInfoToRemove);
- mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
- devInfoToRemove);
- mBrokerHandler.removeEqualMessages(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE,
- devInfoToRemove);
- }
-
- private static final class HearingAidDeviceConnectionInfo {
- final @NonNull BluetoothDevice mDevice;
- final @AudioService.BtProfileConnectionState int mState;
- final boolean mSupprNoisy;
- final int mMusicDevice;
- final @NonNull String mEventSource;
-
- HearingAidDeviceConnectionInfo(@NonNull BluetoothDevice device,
- @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
- mDevice = device;
- mState = state;
- mSupprNoisy = suppressNoisyIntent;
- mMusicDevice = musicDevice;
- mEventSource = eventSource;
- }
- }
-
- /*package*/ void postBluetoothHearingAidDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
- final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo(
- device, state, suppressNoisyIntent, musicDevice, eventSource);
- sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
- }
-
- private static final class LeAudioDeviceConnectionInfo {
- final @NonNull BluetoothDevice mDevice;
- final @AudioService.BtProfileConnectionState int mState;
- final boolean mSupprNoisy;
- final @NonNull String mEventSource;
-
- LeAudioDeviceConnectionInfo(@NonNull BluetoothDevice device,
- @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, @NonNull String eventSource) {
- mDevice = device;
- mState = state;
- mSupprNoisy = suppressNoisyIntent;
- mEventSource = eventSource;
- }
- }
-
- /*package*/ void postBluetoothLeAudioOutDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, @NonNull String eventSource) {
- final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo(
- device, state, suppressNoisyIntent, eventSource);
- sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
- }
-
- /*package*/ void postBluetoothLeAudioInDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- @NonNull String eventSource) {
- final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo(
- device, state, false, eventSource);
- sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
- }
-
/**
* Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
*/
@@ -926,19 +934,8 @@
}
@GuardedBy("mDeviceStateLock")
- /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state,
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
- sendILMsg(state == BluetoothA2dp.STATE_CONNECTED
- ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED
- : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
- SENDMSG_QUEUE,
- state, btDeviceInfo, delay);
- }
-
- /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state,
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
- sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
- state, btDeviceInfo, delay);
+ /*package*/ void postBluetoothActiveDevice(BtDeviceInfo info, int delay) {
+ sendLMsg(MSG_L_SET_BT_ACTIVE_DEVICE, SENDMSG_QUEUE, info, delay);
}
/*package*/ void postSetWiredDeviceConnectionState(
@@ -946,72 +943,12 @@
sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay);
}
- /*package*/ void postSetHearingAidConnectionState(
- @AudioService.BtProfileConnectionState int state,
- @NonNull BluetoothDevice device, int delay) {
- sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE,
- state,
- device,
- delay);
+ /*package*/ void postBtProfileDisconnected(int profile) {
+ sendIMsgNoDelay(MSG_I_BT_SERVICE_DISCONNECTED_PROFILE, SENDMSG_QUEUE, profile);
}
- /*package*/ void postSetLeAudioOutConnectionState(
- @AudioService.BtProfileConnectionState int state,
- @NonNull BluetoothDevice device, int delay) {
- sendILMsg(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE, SENDMSG_QUEUE,
- state,
- device,
- delay);
- }
-
- /*package*/ void postSetLeAudioInConnectionState(
- @AudioService.BtProfileConnectionState int state,
- @NonNull BluetoothDevice device) {
- sendILMsgNoDelay(MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE, SENDMSG_QUEUE,
- state,
- device);
- }
-
- /*package*/ void postDisconnectA2dp() {
- sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE);
- }
-
- /*package*/ void postDisconnectA2dpSink() {
- sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE);
- }
-
- /*package*/ void postDisconnectHearingAid() {
- sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
- }
-
- /*package*/ void postDisconnectLeAudio() {
- sendMsgNoDelay(MSG_DISCONNECT_BT_LE_AUDIO, SENDMSG_QUEUE);
- }
-
- /*package*/ void postDisconnectHeadset() {
- sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
- }
-
- /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile);
- }
-
- /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile);
- }
-
- /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile);
- }
-
- /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE,
- hearingAidProfile);
- }
-
- /*package*/ void postBtLeAudioProfileConnected(BluetoothLeAudio leAudioProfile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO, SENDMSG_QUEUE,
- leAudioProfile);
+ /*package*/ void postBtProfileConnected(int profile, BluetoothProfile proxy) {
+ sendILMsgNoDelay(MSG_IL_BT_SERVICE_CONNECTED_PROFILE, SENDMSG_QUEUE, profile, proxy);
}
/*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) {
@@ -1069,13 +1006,6 @@
}
}
- /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
- final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
- sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state,
- btDeviceInfo);
- }
-
/*package*/ void handleFailureToConnectToBtHeadsetService(int delay) {
sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay);
}
@@ -1088,19 +1018,10 @@
sendMsgNoDelay(fromA2dp ? MSG_REPORT_NEW_ROUTES_A2DP : MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP);
}
- /*package*/ void postA2dpActiveDeviceChange(
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
- sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo);
- }
-
// must be called synchronized on mConnectedDevices
- /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) {
- final BtHelper.BluetoothA2dpDeviceInfo devInfoToCheck =
- new BtHelper.BluetoothA2dpDeviceInfo(btDevice);
- return (mBrokerHandler.hasEqualMessages(
- MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, devInfoToCheck)
- || mBrokerHandler.hasEqualMessages(
- MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, devInfoToCheck));
+ /*package*/ boolean hasScheduledA2dpConnection(BluetoothDevice btDevice) {
+ final BtDeviceInfo devInfoToCheck = new BtDeviceInfo(btDevice, BluetoothProfile.A2DP);
+ return mBrokerHandler.hasEqualMessages(MSG_L_SET_BT_ACTIVE_DEVICE, devInfoToCheck);
}
/*package*/ void setA2dpTimeout(String address, int a2dpCodec, int delayMs) {
@@ -1124,12 +1045,6 @@
}
}
- /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
- synchronized (mDeviceStateLock) {
- return mBtHelper.getA2dpCodec(device);
- }
- }
-
/*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) {
mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent);
}
@@ -1285,39 +1200,11 @@
mDeviceInventory.onReportNewRoutes();
}
break;
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
+ case MSG_L_SET_BT_ACTIVE_DEVICE:
synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetA2dpSinkConnectionState(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
- }
- break;
- case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetA2dpSourceConnectionState(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
- }
- break;
- case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetHearingAidConnectionState(
- (BluetoothDevice) msg.obj, msg.arg1,
+ mDeviceInventory.onSetBtActiveDevice((BtDeviceInfo) msg.obj,
mAudioService.getBluetoothContextualVolumeStream());
}
- break;
- case MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetLeAudioOutConnectionState(
- (BluetoothDevice) msg.obj, msg.arg1,
- mAudioService.getBluetoothContextualVolumeStream());
- }
- break;
- case MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetLeAudioInConnectionState(
- (BluetoothDevice) msg.obj, msg.arg1);
- }
- break;
case MSG_BT_HEADSET_CNCT_FAILED:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
@@ -1332,14 +1219,10 @@
}
break;
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
- final int a2dpCodec;
final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
synchronized (mDeviceStateLock) {
- a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
- // TODO: name of method being called on AudioDeviceInventory is currently
- // misleading (config change vs active device change), to be
- // reconciliated once the BT side has been updated.
- mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
+ final int a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
+ mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec),
BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
}
@@ -1392,96 +1275,47 @@
mDeviceInventory.onToggleHdmi();
}
break;
- case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj,
- BtHelper.EVENT_ACTIVE_DEVICE_CHANGE);
- }
- break;
- case MSG_DISCONNECT_A2DP:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectA2dp();
- }
- break;
- case MSG_DISCONNECT_A2DP_SINK:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectA2dpSink();
- }
- break;
- case MSG_DISCONNECT_BT_HEARING_AID:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectHearingAid();
- }
- break;
- case MSG_DISCONNECT_BT_HEADSET:
- synchronized (mSetModeLock) {
+ case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE:
+ if (msg.arg1 != BluetoothProfile.HEADSET) {
synchronized (mDeviceStateLock) {
- mBtHelper.disconnectHeadset();
+ mDeviceInventory.onBtProfileDisconnected(msg.arg1);
+ }
+ } else {
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mBtHelper.disconnectHeadset();
+ }
}
}
break;
- case MSG_DISCONNECT_BT_LE_AUDIO:
- synchronized(mDeviceStateLock) {
- mDeviceInventory.disconnectLeAudio();
- }
- break;
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
- synchronized (mDeviceStateLock) {
- mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
- }
- break;
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK:
- synchronized (mDeviceStateLock) {
- mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj);
- }
- break;
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID:
- synchronized (mDeviceStateLock) {
- mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
- }
- break;
-
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO:
- synchronized(mDeviceStateLock) {
- mBtHelper.onLeAudioProfileConnected((BluetoothLeAudio) msg.obj);
- }
- break;
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
- synchronized (mSetModeLock) {
+ case MSG_IL_BT_SERVICE_CONNECTED_PROFILE:
+ if (msg.arg1 != BluetoothProfile.HEADSET) {
synchronized (mDeviceStateLock) {
- mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
+ mBtHelper.onBtProfileConnected(msg.arg1, (BluetoothProfile) msg.obj);
+ }
+ } else {
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
+ }
}
}
break;
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: {
- final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
+ case MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT: {
+ final BtDeviceInfo info = (BtDeviceInfo) msg.obj;
+ if (info.mDevice == null) break;
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
- "msg: setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent "
+ "msg: onBluetoothActiveDeviceChange "
+ " state=" + info.mState
// only querying address as this is the only readily available
// field on the device
+ " addr=" + info.mDevice.getAddress()
- + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy
- + " vol=" + info.mVolume)).printLog(TAG));
- synchronized (mDeviceStateLock) {
- mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
- info.mDevice, info.mState, info.mProfile, info.mSupprNoisy,
- AudioSystem.DEVICE_NONE, info.mVolume);
- }
- } break;
- case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: {
- final HearingAidDeviceConnectionInfo info =
- (HearingAidDeviceConnectionInfo) msg.obj;
- AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
- "msg: setHearingAidDeviceConnectionState state=" + info.mState
- + " addr=" + info.mDevice.getAddress()
+ + " prof=" + info.mProfile
+ " supprNoisy=" + info.mSupprNoisy
- + " src=" + info.mEventSource)).printLog(TAG));
+ + " src=" + info.mEventSource
+ )).printLog(TAG));
synchronized (mDeviceStateLock) {
- mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
- info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
+ mDeviceInventory.setBluetoothActiveDevice(info);
}
} break;
case MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY: {
@@ -1524,31 +1358,6 @@
final int capturePreset = msg.arg1;
mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset);
} break;
- case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT: {
- final LeAudioDeviceConnectionInfo info =
- (LeAudioDeviceConnectionInfo) msg.obj;
- AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
- "setLeAudioDeviceOutConnectionState state=" + info.mState
- + " addr=" + info.mDevice.getAddress()
- + " supprNoisy=" + info.mSupprNoisy
- + " src=" + info.mEventSource)).printLog(TAG));
- synchronized (mDeviceStateLock) {
- mDeviceInventory.setBluetoothLeAudioOutDeviceConnectionState(
- info.mDevice, info.mState, info.mSupprNoisy);
- }
- } break;
- case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT: {
- final LeAudioDeviceConnectionInfo info =
- (LeAudioDeviceConnectionInfo) msg.obj;
- AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
- "setLeAudioDeviceInConnectionState state=" + info.mState
- + " addr=" + info.mDevice.getAddress()
- + " src=" + info.mEventSource)).printLog(TAG));
- synchronized (mDeviceStateLock) {
- mDeviceInventory.setBluetoothLeAudioInDeviceConnectionState(info.mDevice,
- info.mState);
- }
- } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1579,8 +1388,7 @@
private static final int MSG_IIL_SET_FORCE_USE = 4;
private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5;
private static final int MSG_TOGGLE_HDMI = 6;
- private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7;
- private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8;
+ private static final int MSG_L_SET_BT_ACTIVE_DEVICE = 7;
private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
private static final int MSG_IL_BTA2DP_TIMEOUT = 10;
@@ -1593,25 +1401,11 @@
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
private static final int MSG_I_SET_MODE_OWNER_PID = 16;
- // process active A2DP device change, obj is BtHelper.BluetoothA2dpDeviceInfo
- private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
-
- private static final int MSG_DISCONNECT_A2DP = 19;
- private static final int MSG_DISCONNECT_A2DP_SINK = 20;
- private static final int MSG_DISCONNECT_BT_HEARING_AID = 21;
- private static final int MSG_DISCONNECT_BT_HEADSET = 22;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
-
- // process change of state, obj is BtHelper.BluetoothA2dpDeviceInfo
- private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27;
- private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28;
+ private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
+ private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
// process external command to (dis)connect an A2DP device, obj is BtDeviceConnectionInfo
- private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29;
- private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30;
+ private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 29;
// process external command to (dis)connect a hearing aid device
private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
@@ -1630,33 +1424,21 @@
private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
- private static final int MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE = 42;
- private static final int MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE = 43;
- private static final int MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT = 44;
- private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45;
+ private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
+ //
// process set volume for Le Audio, obj is BleVolumeInfo
private static final int MSG_II_SET_LE_AUDIO_OUT_VOLUME = 46;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO = 47;
- private static final int MSG_DISCONNECT_BT_LE_AUDIO = 48;
-
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
- case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
- case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
+ case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
case MSG_TOGGLE_HDMI:
- case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
+ case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_CHECK_MUTE_MUSIC:
- case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT:
- case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT:
return true;
default:
return false;
@@ -1739,14 +1521,10 @@
long time = SystemClock.uptimeMillis() + delay;
switch (msg) {
- case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
- case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
+ case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
- case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
if (sLastDeviceConnectMsgTime >= time) {
// add a little delay to make sure messages are ordered as expected
time = sLastDeviceConnectMsgTime + 30;
@@ -1765,14 +1543,9 @@
private static final Set<Integer> MESSAGES_MUTE_MUSIC;
static {
MESSAGES_MUTE_MUSIC = new HashSet<>();
- MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED);
- MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED);
- MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE);
+ MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE);
- MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE);
- MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION);
- MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION);
- MESSAGES_MUTE_MUSIC.add(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT);
+ MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT);
MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE);
MESSAGES_MUTE_MUSIC.add(MSG_REPORT_NEW_ROUTES_A2DP);
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 6c3c736..0a114b9 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -16,11 +16,8 @@
package com.android.server.audio;
import android.annotation.NonNull;
-import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
@@ -286,186 +283,102 @@
}
}
- // only public for mocking/spying
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- @VisibleForTesting
- public void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo,
- @AudioService.BtProfileConnectionState int state) {
- final BluetoothDevice btDevice = btInfo.getBtDevice();
- int a2dpVolume = btInfo.getVolume();
+ void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int streamType) {
if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state="
- + state + " vol=" + a2dpVolume);
+ Log.d(TAG, "onSetBtActiveDevice"
+ + " btDevice=" + btInfo.mDevice
+ + " profile=" + BluetoothProfile.getProfileName(btInfo.mProfile)
+ + " state=" + BluetoothProfile.getConnectionStateName(btInfo.mState));
}
- String address = btDevice.getAddress();
- if (address == null) {
- address = "";
- }
+ String address = btInfo.mDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
- final @AudioSystem.AudioFormatNativeEnumForBtCodec int a2dpCodec = btInfo.getCodec();
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent("BT connected:"
+ + " addr=" + address
+ + " profile=" + btInfo.mProfile
+ + " state=" + btInfo.mState
+ + " codec=" + AudioSystem.audioFormatToString(btInfo.mCodec)));
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "A2DP sink connected: device addr=" + address + " state=" + state
- + " codec=" + AudioSystem.audioFormatToString(a2dpCodec)
- + " vol=" + a2dpVolume));
-
- new MediaMetrics.Item(mMetricsId + "a2dp")
+ new MediaMetrics.Item(mMetricsId + "onSetBtActiveDevice")
+ .set(MediaMetrics.Property.STATUS, btInfo.mProfile)
+ .set(MediaMetrics.Property.DEVICE,
+ AudioSystem.getDeviceName(btInfo.mAudioSystemDevice))
.set(MediaMetrics.Property.ADDRESS, address)
- .set(MediaMetrics.Property.ENCODING, AudioSystem.audioFormatToString(a2dpCodec))
- .set(MediaMetrics.Property.EVENT, "onSetA2dpSinkConnectionState")
- .set(MediaMetrics.Property.INDEX, a2dpVolume)
+ .set(MediaMetrics.Property.ENCODING,
+ AudioSystem.audioFormatToString(btInfo.mCodec))
+ .set(MediaMetrics.Property.EVENT, "onSetBtActiveDevice")
+ .set(MediaMetrics.Property.STREAM_TYPE,
+ AudioSystem.streamToString(streamType))
.set(MediaMetrics.Property.STATE,
- state == BluetoothProfile.STATE_CONNECTED
+ btInfo.mState == BluetoothProfile.STATE_CONNECTED
? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
.record();
synchronized (mDevicesLock) {
- final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- btDevice.getAddress());
+ final String key = DeviceInfo.makeDeviceListKey(btInfo.mAudioSystemDevice, address);
final DeviceInfo di = mConnectedDevices.get(key);
- boolean isConnected = di != null;
- if (isConnected) {
- if (state == BluetoothProfile.STATE_CONNECTED) {
- // device is already connected, but we are receiving a connection again,
- // it could be for a codec change
- if (a2dpCodec != di.mDeviceCodecFormat) {
- mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice);
+ final boolean isConnected = di != null;
+
+ final boolean switchToUnavailable = isConnected
+ && btInfo.mState != BluetoothProfile.STATE_CONNECTED;
+ final boolean switchToAvailable = !isConnected
+ && btInfo.mState == BluetoothProfile.STATE_CONNECTED;
+
+ switch (btInfo.mProfile) {
+ case BluetoothProfile.A2DP_SINK:
+ if (switchToUnavailable) {
+ makeA2dpSrcUnavailable(address);
+ } else if (switchToAvailable) {
+ makeA2dpSrcAvailable(address);
}
- } else {
- makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
- }
- } else if (state == BluetoothProfile.STATE_CONNECTED) {
- // device is not already connected
- if (a2dpVolume != -1) {
- mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
- // convert index to internal representation in VolumeStreamState
- a2dpVolume * 10,
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
- }
- makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
- "onSetA2dpSinkConnectionState", a2dpCodec);
+ break;
+ case BluetoothProfile.A2DP:
+ if (switchToUnavailable) {
+ makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
+ } else if (switchToAvailable) {
+ // device is not already connected
+ if (btInfo.mVolume != -1) {
+ mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+ // convert index to internal representation in VolumeStreamState
+ btInfo.mVolume * 10, btInfo.mAudioSystemDevice,
+ "onSetBtActiveDevice");
+ }
+ makeA2dpDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
+ "onSetBtActiveDevice", btInfo.mCodec);
+ }
+ break;
+ case BluetoothProfile.HEARING_AID:
+ if (switchToUnavailable) {
+ makeHearingAidDeviceUnavailable(address);
+ } else if (switchToAvailable) {
+ makeHearingAidDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
+ streamType, "onSetBtActiveDevice");
+ }
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ if (switchToUnavailable) {
+ makeLeAudioDeviceUnavailable(address, btInfo.mAudioSystemDevice);
+ } else if (switchToAvailable) {
+ makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
+ streamType, btInfo.mAudioSystemDevice, "onSetBtActiveDevice");
+ }
+ break;
+ default: throw new IllegalArgumentException("Invalid profile "
+ + BluetoothProfile.getProfileName(btInfo.mProfile));
}
}
}
- /*package*/ void onSetA2dpSourceConnectionState(
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int state) {
- final BluetoothDevice btDevice = btInfo.getBtDevice();
- if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state="
- + state);
- }
- String address = btDevice.getAddress();
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- address = "";
- }
-
- synchronized (mDevicesLock) {
- final String key = DeviceInfo.makeDeviceListKey(
- AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
- final DeviceInfo di = mConnectedDevices.get(key);
- boolean isConnected = di != null;
-
- new MediaMetrics.Item(mMetricsId + "onSetA2dpSourceConnectionState")
- .set(MediaMetrics.Property.ADDRESS, address)
- .set(MediaMetrics.Property.DEVICE,
- AudioSystem.getDeviceName(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP))
- .set(MediaMetrics.Property.STATE,
- state == BluetoothProfile.STATE_CONNECTED
- ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
- .record();
-
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- makeA2dpSrcUnavailable(address);
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- makeA2dpSrcAvailable(address);
- }
- }
- }
-
- /*package*/ void onSetHearingAidConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state, int streamType) {
- String address = btDevice.getAddress();
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- address = "";
- }
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "onSetHearingAidConnectionState addr=" + address));
-
- new MediaMetrics.Item(mMetricsId + "onSetHearingAidConnectionState")
- .set(MediaMetrics.Property.ADDRESS, address)
- .set(MediaMetrics.Property.DEVICE,
- AudioSystem.getDeviceName(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP))
- .set(MediaMetrics.Property.STATE,
- state == BluetoothProfile.STATE_CONNECTED
- ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
- .set(MediaMetrics.Property.STREAM_TYPE,
- AudioSystem.streamToString(streamType))
- .record();
-
- synchronized (mDevicesLock) {
- final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID,
- btDevice.getAddress());
- final DeviceInfo di = mConnectedDevices.get(key);
- boolean isConnected = di != null;
-
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- makeHearingAidDeviceUnavailable(address);
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- makeHearingAidDeviceAvailable(address, BtHelper.getName(btDevice), streamType,
- "onSetHearingAidConnectionState");
- }
- }
- }
-
- /*package*/ void onSetLeAudioConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state, int streamType, int device) {
- String address = btDevice.getAddress();
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- address = "";
- }
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "onSetLeAudioConnectionState addr=" + address));
-
- synchronized (mDevicesLock) {
- DeviceInfo di = null;
- boolean isConnected = false;
-
- String key = DeviceInfo.makeDeviceListKey(device, btDevice.getAddress());
- di = mConnectedDevices.get(key);
- isConnected = di != null;
-
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- makeLeAudioDeviceUnavailable(address, device);
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- makeLeAudioDeviceAvailable(address, BtHelper.getName(btDevice), streamType,
- device, "onSetLeAudioConnectionState");
- }
- }
- }
-
- /*package*/ void onSetLeAudioOutConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state, int streamType) {
- // TODO: b/198610537 clarify DEVICE_OUT_BLE_HEADSET vs DEVICE_OUT_BLE_SPEAKER criteria
- onSetLeAudioConnectionState(btDevice, state, streamType,
- AudioSystem.DEVICE_OUT_BLE_HEADSET);
- }
-
- /*package*/ void onSetLeAudioInConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state) {
- onSetLeAudioConnectionState(btDevice, state, AudioSystem.STREAM_DEFAULT,
- AudioSystem.DEVICE_IN_BLE_HEADSET);
- }
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- /*package*/ void onBluetoothA2dpActiveDeviceChange(
+ /*package*/ void onBluetoothA2dpDeviceConfigChange(
@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
- + "onBluetoothA2dpActiveDeviceChange")
+ + "onBluetoothA2dpDeviceConfigChange")
.set(MediaMetrics.Property.EVENT, BtHelper.a2dpDeviceEventToString(event));
final BluetoothDevice btDevice = btInfo.getBtDevice();
@@ -474,7 +387,7 @@
return;
}
if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onBluetoothA2dpActiveDeviceChange btDevice=" + btDevice);
+ Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
}
int a2dpVolume = btInfo.getVolume();
@AudioSystem.AudioFormatNativeEnumForBtCodec final int a2dpCodec = btInfo.getCodec();
@@ -484,11 +397,11 @@
address = "";
}
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "onBluetoothA2dpActiveDeviceChange addr=" + address
+ "onBluetoothA2dpDeviceConfigChange addr=" + address
+ " event=" + BtHelper.a2dpDeviceEventToString(event)));
synchronized (mDevicesLock) {
- if (mDeviceBroker.hasScheduledA2dpSinkConnectionState(btDevice)) {
+ if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) {
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
"A2dp config change ignored (scheduled connection change)")
.printLog(TAG));
@@ -500,7 +413,7 @@
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
final DeviceInfo di = mConnectedDevices.get(key);
if (di == null) {
- Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpActiveDeviceChange");
+ Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpDeviceConfigChange");
mmi.set(MediaMetrics.Property.EARLY_RETURN, "null DeviceInfo").record();
return;
}
@@ -518,7 +431,7 @@
// convert index to internal representation in VolumeStreamState
a2dpVolume * 10,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- "onBluetoothA2dpActiveDeviceChange");
+ "onBluetoothA2dpDeviceConfigChange");
}
} else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
if (di.mDeviceCodecFormat != a2dpCodec) {
@@ -539,10 +452,9 @@
int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
// force A2DP device disconnection in case of error so that AudioService state is
// consistent with audio policy manager state
- setBluetoothA2dpDeviceConnectionState(
- btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
- false /* suppressNoisyIntent */, musicDevice,
- -1 /* a2dpVolume */);
+ setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btDevice,
+ BluetoothProfile.A2DP, BluetoothProfile.STATE_DISCONNECTED,
+ musicDevice, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
} else {
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
"APM handleDeviceConfigChange success for A2DP device addr=" + address
@@ -828,7 +740,7 @@
}
- /*package*/ void disconnectA2dp() {
+ private void disconnectA2dp() {
synchronized (mDevicesLock) {
final ArraySet<String> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
@@ -850,7 +762,7 @@
}
}
- /*package*/ void disconnectA2dpSink() {
+ private void disconnectA2dpSink() {
synchronized (mDevicesLock) {
final ArraySet<String> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
@@ -865,7 +777,7 @@
}
}
- /*package*/ void disconnectHearingAid() {
+ private void disconnectHearingAid() {
synchronized (mDevicesLock) {
final ArraySet<String> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_OUT_HEARING_AID devices
@@ -887,6 +799,28 @@
}
}
+ /*package*/ synchronized void onBtProfileDisconnected(int profile) {
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ disconnectA2dp();
+ break;
+ case BluetoothProfile.A2DP_SINK:
+ disconnectA2dpSink();
+ break;
+ case BluetoothProfile.HEARING_AID:
+ disconnectHearingAid();
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ disconnectLeAudio();
+ break;
+ default:
+ // Not a valid profile to disconnect
+ Log.e(TAG, "onBtProfileDisconnected: Not a valid profile to disconnect "
+ + BluetoothProfile.getProfileName(profile));
+ break;
+ }
+ }
+
/*package*/ void disconnectLeAudio() {
synchronized (mDevicesLock) {
final ArraySet<String> toRemove = new ArraySet<>();
@@ -934,46 +868,39 @@
// only public for mocking/spying
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@VisibleForTesting
- public void setBluetoothA2dpDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- int profile, boolean suppressNoisyIntent, int musicDevice, int a2dpVolume) {
+ public int setBluetoothActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo info) {
int delay;
- if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
- throw new IllegalArgumentException("invalid profile " + profile);
- }
synchronized (mDevicesLock) {
- if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) {
+ if (!info.mSupprNoisy
+ && ((info.mProfile == BluetoothProfile.LE_AUDIO && info.mIsLeOutput)
+ || info.mProfile == BluetoothProfile.HEARING_AID
+ || info.mProfile == BluetoothProfile.A2DP)) {
@AudioService.ConnectionState int asState =
- (state == BluetoothA2dp.STATE_CONNECTED)
+ (info.mState == BluetoothProfile.STATE_CONNECTED)
? AudioService.CONNECTION_STATE_CONNECTED
: AudioService.CONNECTION_STATE_DISCONNECTED;
- delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- asState, musicDevice);
+ delay = checkSendBecomingNoisyIntentInt(info.mAudioSystemDevice, asState,
+ info.mMusicDevice);
} else {
delay = 0;
}
- final int a2dpCodec = mDeviceBroker.getA2dpCodec(device);
-
if (AudioService.DEBUG_DEVICES) {
- Log.i(TAG, "setBluetoothA2dpDeviceConnectionState device: " + device
- + " state: " + state + " delay(ms): " + delay
- + " codec:" + Integer.toHexString(a2dpCodec)
- + " suppressNoisyIntent: " + suppressNoisyIntent);
+ Log.i(TAG, "setBluetoothActiveDevice device: " + info.mDevice
+ + " profile: " + BluetoothProfile.getProfileName(info.mProfile)
+ + " state: " + BluetoothProfile.getConnectionStateName(info.mState)
+ + " delay(ms): " + delay
+ + " codec:" + Integer.toHexString(info.mCodec)
+ + " suppressNoisyIntent: " + info.mSupprNoisy);
}
-
- final BtHelper.BluetoothA2dpDeviceInfo a2dpDeviceInfo =
- new BtHelper.BluetoothA2dpDeviceInfo(device, a2dpVolume, a2dpCodec);
- if (profile == BluetoothProfile.A2DP) {
- mDeviceBroker.postA2dpSinkConnection(state,
- a2dpDeviceInfo,
- delay);
- } else { //profile == BluetoothProfile.A2DP_SINK
- mDeviceBroker.postA2dpSourceConnection(state,
- a2dpDeviceInfo,
- delay);
+ mDeviceBroker.postBluetoothActiveDevice(info, delay);
+ if (info.mProfile == BluetoothProfile.HEARING_AID
+ && info.mState == BluetoothProfile.STATE_CONNECTED) {
+ mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE,
+ "HEARING_AID set to CONNECTED");
}
}
+ return delay;
}
/*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
@@ -987,50 +914,6 @@
}
}
- /*package*/ int setBluetoothHearingAidDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, int musicDevice) {
- int delay;
- synchronized (mDevicesLock) {
- if (!suppressNoisyIntent) {
- int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
- delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_HEARING_AID,
- intState, musicDevice);
- } else {
- delay = 0;
- }
- mDeviceBroker.postSetHearingAidConnectionState(state, device, delay);
- if (state == BluetoothHearingAid.STATE_CONNECTED) {
- mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE,
- "HEARING_AID set to CONNECTED");
- }
- return delay;
- }
- }
-
- /*package*/ int setBluetoothLeAudioOutDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent) {
- synchronized (mDevicesLock) {
- /* Active device become null and it's previous device is not connected anymore */
- int delay = 0;
- if (!suppressNoisyIntent) {
- int intState = (state == BluetoothLeAudio.STATE_CONNECTED) ? 1 : 0;
- delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLE_HEADSET,
- intState, AudioSystem.DEVICE_NONE);
- }
- mDeviceBroker.postSetLeAudioOutConnectionState(state, device, delay);
- return delay;
- }
- }
-
- /*package*/ void setBluetoothLeAudioInDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state) {
- synchronized (mDevicesLock) {
- mDeviceBroker.postSetLeAudioInConnectionState(state, device);
- }
- }
-
//-------------------------------------------------------------------
// Internal utilities
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d75f21c..51784bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -83,6 +83,7 @@
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
+import android.media.BtProfileConnectionInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -309,8 +310,8 @@
private static final int MSG_UPDATE_A11Y_SERVICE_UIDS = 35;
private static final int MSG_UPDATE_AUDIO_MODE = 36;
private static final int MSG_RECORDING_CONFIG_CHANGE = 37;
- private static final int MSG_SET_A2DP_DEV_CONNECTION_STATE = 38;
- private static final int MSG_A2DP_DEV_CONFIG_CHANGE = 39;
+ private static final int MSG_BT_DEV_CHANGED = 38;
+
private static final int MSG_DISPATCH_AUDIO_MODE = 40;
// start of messages handled under wakelock
@@ -6266,77 +6267,44 @@
public @interface BtProfileConnectionState {}
/**
- * See AudioManager.setBluetoothHearingAidDeviceConnectionState()
+ * @hide
+ * The profiles that can be used with AudioService.handleBluetoothActiveDeviceChanged()
*/
- public void setBluetoothHearingAidDeviceConnectionState(
- @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
- boolean suppressNoisyIntent, int musicDevice)
- {
- if (device == null) {
- throw new IllegalArgumentException("Illegal null device");
- }
- if (state != BluetoothProfile.STATE_CONNECTED
- && state != BluetoothProfile.STATE_DISCONNECTED) {
- throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
- + " (dis)connection, got " + state);
- }
- mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
- device, state, suppressNoisyIntent, musicDevice, "AudioService");
- }
+ @IntDef({
+ BluetoothProfile.HEARING_AID,
+ BluetoothProfile.A2DP,
+ BluetoothProfile.A2DP_SINK,
+ BluetoothProfile.LE_AUDIO,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BtProfile {}
- private void setBluetoothLeAudioDeviceConnectionState(@NonNull BluetoothDevice device,
- @BtProfileConnectionState int state) {
- if (device == null) {
- throw new IllegalArgumentException("Illegal null device");
- }
- if (state != BluetoothProfile.STATE_CONNECTED
- && state != BluetoothProfile.STATE_DISCONNECTED) {
- throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
- + " (dis)connection, got " + state);
- }
- }
/**
- * See AudioManager.setBluetoothLeAudioOutDeviceConnectionState()
+ * See AudioManager.handleBluetoothActiveDeviceChanged(...)
*/
- public void setBluetoothLeAudioOutDeviceConnectionState(
- @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
- boolean suppressNoisyIntent) {
- setBluetoothLeAudioDeviceConnectionState(device, state);
- mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(device, state,
- suppressNoisyIntent, "AudioService");
- }
-
- /**
- * See AudioManager.setBluetoothLeAudioInDeviceConnectionState()
- */
- public void setBluetoothLeAudioInDeviceConnectionState(
- @NonNull BluetoothDevice device, @BtProfileConnectionState int state) {
- setBluetoothLeAudioDeviceConnectionState(device, state);
- mDeviceBroker.postBluetoothLeAudioInDeviceConnectionState(device, state, "AudioService");
- }
-
- /**
- * See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent()
- */
- public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
- int profile, boolean suppressNoisyIntent, int a2dpVolume) {
- if (device == null) {
- throw new IllegalArgumentException("Illegal null device");
+ public void handleBluetoothActiveDeviceChanged(BluetoothDevice newDevice,
+ BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Bluetooth is the only caller allowed");
}
- if (state != BluetoothProfile.STATE_CONNECTED
- && state != BluetoothProfile.STATE_DISCONNECTED) {
- throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
- + " (dis)connection, got " + state);
+ if (info == null) {
+ throw new IllegalArgumentException("Illegal null BtProfileConnectionInfo for device "
+ + previousDevice + " -> " + newDevice);
}
-
- AudioDeviceBroker.BtDeviceConnectionInfo info =
- new AudioDeviceBroker.BtDeviceConnectionInfo(device, state,
- profile, suppressNoisyIntent, a2dpVolume);
- sendMsg(mAudioHandler, MSG_SET_A2DP_DEV_CONNECTION_STATE, SENDMSG_QUEUE,
- 0 /*arg1*/, 0 /*arg2*/,
- /*obj*/ info, 0 /*delay*/);
+ final int profile = info.getProfile();
+ if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK
+ && profile != BluetoothProfile.LE_AUDIO
+ && profile != BluetoothProfile.HEARING_AID) {
+ throw new IllegalArgumentException("Illegal BluetoothProfile profile for device "
+ + previousDevice + " -> " + newDevice + ". Got: " + profile);
+ }
+ AudioDeviceBroker.BtDeviceChangedData data =
+ new AudioDeviceBroker.BtDeviceChangedData(newDevice, previousDevice, info,
+ "AudioService");
+ sendMsg(mAudioHandler, MSG_BT_DEV_CHANGED, SENDMSG_QUEUE, 0, 0,
+ /*obj*/ data, /*delay*/ 0);
}
/** only public for mocking/spying, do not call outside of AudioService */
@@ -6345,19 +6313,6 @@
mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute);
}
- /**
- * See AudioManager.handleBluetoothA2dpDeviceConfigChange()
- * @param device
- */
- public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
- {
- if (device == null) {
- throw new IllegalArgumentException("Illegal null device");
- }
- sendMsg(mAudioHandler, MSG_A2DP_DEV_CONFIG_CHANGE, SENDMSG_QUEUE, 0, 0,
- /*obj*/ device, /*delay*/ 0);
- }
-
private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET;
static {
DEVICE_MEDIA_UNMUTED_ON_PLUG_SET = new HashSet<>();
@@ -7709,13 +7664,9 @@
}
break;
- case MSG_SET_A2DP_DEV_CONNECTION_STATE:
- mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- (AudioDeviceBroker.BtDeviceConnectionInfo) msg.obj);
- break;
-
- case MSG_A2DP_DEV_CONFIG_CHANGE:
- mDeviceBroker.postBluetoothA2dpDeviceConfigChange((BluetoothDevice) msg.obj);
+ case MSG_BT_DEV_CHANGED:
+ mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ (AudioDeviceBroker.BtDeviceChangedData) msg.obj);
break;
case MSG_DISPATCH_AUDIO_MODE:
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index c924fde..9273a5d 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -31,6 +31,7 @@
import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
+import android.media.BtProfileConnectionInfo;
import android.os.Binder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -451,11 +452,11 @@
}
/*package*/ synchronized void disconnectAllBluetoothProfiles() {
- mDeviceBroker.postDisconnectA2dp();
- mDeviceBroker.postDisconnectA2dpSink();
- mDeviceBroker.postDisconnectHeadset();
- mDeviceBroker.postDisconnectHearingAid();
- mDeviceBroker.postDisconnectLeAudio();
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.A2DP);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.A2DP_SINK);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEADSET);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEARING_AID);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.LE_AUDIO);
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@@ -474,63 +475,32 @@
mBluetoothHeadset = null;
}
- /*package*/ synchronized void onA2dpProfileConnected(BluetoothA2dp a2dp) {
- mA2dp = a2dp;
- final List<BluetoothDevice> deviceList = mA2dp.getConnectedDevices();
- if (deviceList.isEmpty()) {
+ /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
+ if (profile == BluetoothProfile.HEADSET) {
+ onHeadsetProfileConnected((BluetoothHeadset) proxy);
return;
}
- final BluetoothDevice btDevice = deviceList.get(0);
- // the device is guaranteed CONNECTED
- mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(btDevice,
- BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK,
- true, -1));
- }
-
- /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) {
- final List<BluetoothDevice> deviceList = profile.getConnectedDevices();
+ if (profile == BluetoothProfile.A2DP) {
+ mA2dp = (BluetoothA2dp) proxy;
+ } else if (profile == BluetoothProfile.LE_AUDIO) {
+ mLeAudio = (BluetoothLeAudio) proxy;
+ }
+ final List<BluetoothDevice> deviceList = proxy.getConnectedDevices();
if (deviceList.isEmpty()) {
return;
}
final BluetoothDevice btDevice = deviceList.get(0);
final @BluetoothProfile.BtProfileState int state =
- profile.getConnectionState(btDevice);
- mDeviceBroker.postSetA2dpSourceConnectionState(
- state, new BluetoothA2dpDeviceInfo(btDevice));
- }
-
- /*package*/ synchronized void onHearingAidProfileConnected(BluetoothHearingAid hearingAid) {
- mHearingAid = hearingAid;
- final List<BluetoothDevice> deviceList = mHearingAid.getConnectedDevices();
- if (deviceList.isEmpty()) {
- return;
+ proxy.getConnectionState(btDevice);
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(btDevice, null,
+ new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener"));
+ } else {
+ mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(null, btDevice,
+ new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener"));
}
- final BluetoothDevice btDevice = deviceList.get(0);
- final @BluetoothProfile.BtProfileState int state =
- mHearingAid.getConnectionState(btDevice);
- mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
- btDevice, state,
- /*suppressNoisyIntent*/ false,
- /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
- /*eventSource*/ "mBluetoothProfileServiceListener");
- }
-
- /*package*/ synchronized void onLeAudioProfileConnected(BluetoothLeAudio leAudio) {
- mLeAudio = leAudio;
- final List<BluetoothDevice> deviceList = mLeAudio.getConnectedDevices();
- if (deviceList.isEmpty()) {
- return;
- }
-
- final BluetoothDevice btDevice = deviceList.get(0);
- final @BluetoothProfile.BtProfileState int state =
- mLeAudio.getConnectionState(btDevice);
- mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(
- btDevice, state,
- /*suppressNoisyIntent*/ false,
- /*musicDevice android.media.AudioSystem.DEVICE_NONE,*/
- /*eventSource*/ "mBluetoothProfileServiceListener");
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@@ -677,36 +647,16 @@
public void onServiceConnected(int profile, BluetoothProfile proxy) {
switch(profile) {
case BluetoothProfile.A2DP:
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting A2DP profile"));
- mDeviceBroker.postBtA2dpProfileConnected((BluetoothA2dp) proxy);
- break;
-
case BluetoothProfile.A2DP_SINK:
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting A2DP_SINK profile"));
- mDeviceBroker.postBtA2dpSinkProfileConnected(proxy);
- break;
-
case BluetoothProfile.HEADSET:
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting HEADSET profile"));
- mDeviceBroker.postBtHeasetProfileConnected((BluetoothHeadset) proxy);
- break;
-
case BluetoothProfile.HEARING_AID:
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting HEARING_AID profile"));
- mDeviceBroker.postBtHearingAidProfileConnected(
- (BluetoothHearingAid) proxy);
- break;
-
case BluetoothProfile.LE_AUDIO:
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting LE_AUDIO profile"));
- mDeviceBroker.postBtLeAudioProfileConnected(
- (BluetoothLeAudio) proxy);
+ "BT profile service: connecting "
+ + BluetoothProfile.getProfileName(profile) + " profile"));
+ mDeviceBroker.postBtProfileConnected(profile, proxy);
break;
+
default:
break;
}
@@ -715,22 +665,11 @@
switch (profile) {
case BluetoothProfile.A2DP:
- mDeviceBroker.postDisconnectA2dp();
- break;
-
case BluetoothProfile.A2DP_SINK:
- mDeviceBroker.postDisconnectA2dpSink();
- break;
-
case BluetoothProfile.HEADSET:
- mDeviceBroker.postDisconnectHeadset();
- break;
-
case BluetoothProfile.HEARING_AID:
- mDeviceBroker.postDisconnectHearingAid();
- break;
case BluetoothProfile.LE_AUDIO:
- mDeviceBroker.postDisconnectLeAudio();
+ mDeviceBroker.postBtProfileDisconnected(profile);
break;
default:
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 0cd2e3d..c97ad55 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -60,6 +60,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -70,6 +71,7 @@
import com.android.server.SystemService;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -81,6 +83,8 @@
private static final String SETTING_HIDL_DISABLED =
"com.android.server.biometrics.AuthService.hidlDisabled";
private static final int DEFAULT_HIDL_DISABLED = 0;
+ private static final String SYSPROP_FIRST_API_LEVEL = "ro.board.first_api_level";
+ private static final String SYSPROP_API_LEVEL = "ro.board.api_level";
private final Injector mInjector;
@@ -623,7 +627,16 @@
final SensorConfig[] hidlConfigs;
if (!mInjector.isHidlDisabled(getContext())) {
- final String[] configStrings = mInjector.getConfiguration(getContext());
+ final int firstApiLevel = SystemProperties.getInt(SYSPROP_FIRST_API_LEVEL, 0);
+ final int apiLevel = SystemProperties.getInt(SYSPROP_API_LEVEL, firstApiLevel);
+ String[] configStrings = mInjector.getConfiguration(getContext());
+ if (configStrings.length == 0 && apiLevel == Build.VERSION_CODES.R) {
+ // For backwards compatibility with R where biometrics could work without being
+ // configured in config_biometric_sensors. In the absence of a vendor provided
+ // configuration, we assume the weakest biometric strength (i.e. convenience).
+ Slog.w(TAG, "Found R vendor partition without config_biometric_sensors");
+ configStrings = generateRSdkCompatibleConfiguration();
+ }
hidlConfigs = new SensorConfig[configStrings.length];
for (int i = 0; i < configStrings.length; ++i) {
hidlConfigs[i] = new SensorConfig(configStrings[i]);
@@ -639,6 +652,31 @@
}
/**
+ * Generates an array of string configs with entries that correspond to the biometric features
+ * declared on the device. Returns an empty array if no biometric features are declared.
+ * Biometrics are assumed to be of the weakest strength class, i.e. convenience.
+ */
+ private @NonNull String[] generateRSdkCompatibleConfiguration() {
+ final PackageManager pm = getContext().getPackageManager();
+ final ArrayList<String> modalities = new ArrayList<>();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ modalities.add(String.valueOf(BiometricAuthenticator.TYPE_FINGERPRINT));
+ }
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ modalities.add(String.valueOf(BiometricAuthenticator.TYPE_FACE));
+ }
+ final String strength = String.valueOf(Authenticators.BIOMETRIC_CONVENIENCE);
+ final String[] configStrings = new String[modalities.size()];
+ for (int i = 0; i < modalities.size(); ++i) {
+ final String id = String.valueOf(i);
+ final String modality = modalities.get(i);
+ configStrings[i] = String.join(":" /* delimiter */, id, modality, strength);
+ }
+ Slog.d(TAG, "Generated config_biometric_sensors: " + Arrays.toString(configStrings));
+ return configStrings;
+ }
+
+ /**
* Registers HIDL and AIDL authenticators for all of the available modalities.
*
* @param hidlSensors Array of {@link SensorConfig} configuration for all of the HIDL sensors
diff --git a/services/core/java/com/android/server/compat/OWNERS b/services/core/java/com/android/server/compat/OWNERS
index cfd0a4b..ee3086a 100644
--- a/services/core/java/com/android/server/compat/OWNERS
+++ b/services/core/java/com/android/server/compat/OWNERS
@@ -1,6 +1 @@
-# Use this reviewer by default.
-platform-compat-eng+reviews@google.com
-
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+include tools/platform-compat:/OWNERS
diff --git a/services/core/java/com/android/server/health/HealthHalCallbackHidl.java b/services/core/java/com/android/server/health/HealthHalCallbackHidl.java
new file mode 100644
index 0000000..7a66980
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthHalCallbackHidl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.health;
+
+import static android.hardware.health.Translate.h2aTranslate;
+
+import android.annotation.NonNull;
+import android.hardware.health.V2_0.IHealth;
+import android.hardware.health.V2_0.Result;
+import android.hardware.health.V2_1.BatteryCapacityLevel;
+import android.hardware.health.V2_1.Constants;
+import android.hardware.health.V2_1.IHealthInfoCallback;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Slog;
+
+/**
+ * On service registration, {@link HealthServiceWrapperHidl.Callback#onRegistration} is called,
+ * which registers {@code this}, a {@link IHealthInfoCallback}, to the health service.
+ *
+ * <p>When the health service has updates to health info, {@link HealthInfoCallback#update} is
+ * called.
+ *
+ * @hide
+ */
+class HealthHalCallbackHidl extends IHealthInfoCallback.Stub
+ implements HealthServiceWrapperHidl.Callback {
+
+ private static final String TAG = HealthHalCallbackHidl.class.getSimpleName();
+
+ private static void traceBegin(String name) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+ }
+
+ private static void traceEnd() {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ private HealthInfoCallback mCallback;
+
+ HealthHalCallbackHidl(@NonNull HealthInfoCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
+ android.hardware.health.V2_1.HealthInfo propsLatest =
+ new android.hardware.health.V2_1.HealthInfo();
+ propsLatest.legacy = props;
+
+ propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED;
+ propsLatest.batteryChargeTimeToFullNowSeconds =
+ Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
+
+ mCallback.update(h2aTranslate(propsLatest));
+ }
+
+ @Override
+ public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) {
+ mCallback.update(h2aTranslate(props));
+ }
+
+ // on new service registered
+ @Override
+ public void onRegistration(IHealth oldService, IHealth newService, String instance) {
+ if (newService == null) return;
+
+ traceBegin("HealthUnregisterCallback");
+ try {
+ if (oldService != null) {
+ int r = oldService.unregisterCallback(this);
+ if (r != Result.SUCCESS) {
+ Slog.w(
+ TAG,
+ "health: cannot unregister previous callback: " + Result.toString(r));
+ }
+ }
+ } catch (RemoteException ex) {
+ Slog.w(
+ TAG,
+ "health: cannot unregister previous callback (transaction error): "
+ + ex.getMessage());
+ } finally {
+ traceEnd();
+ }
+
+ traceBegin("HealthRegisterCallback");
+ try {
+ int r = newService.registerCallback(this);
+ if (r != Result.SUCCESS) {
+ Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
+ return;
+ }
+ // registerCallback does NOT guarantee that update is called
+ // immediately, so request a manual update here.
+ newService.update();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "health: cannot register callback (transaction error): " + ex.getMessage());
+ } finally {
+ traceEnd();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/health/HealthInfoCallback.java b/services/core/java/com/android/server/health/HealthInfoCallback.java
new file mode 100644
index 0000000..c2a77fc
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthInfoCallback.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.health;
+
+/**
+ * A wrapper over HIDL / AIDL IHealthInfoCallback.
+ *
+ * @hide
+ */
+public interface HealthInfoCallback {
+ /**
+ * Signals to the client that health info is changed.
+ *
+ * @param props the new health info.
+ */
+ void update(android.hardware.health.HealthInfo props);
+}
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapper.java b/services/core/java/com/android/server/health/HealthServiceWrapper.java
new file mode 100644
index 0000000..9b97554
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthServiceWrapper.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.health;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.BatteryProperty;
+import android.os.HandlerThread;
+import android.os.IBatteryPropertiesRegistrar;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+
+/**
+ * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when necessary.
+ * This is essentially a wrapper over IHealth that is useful for BatteryService.
+ *
+ * <p>The implementation may be backed by a HIDL or AIDL HAL.
+ *
+ * <p>On new registration of IHealth service, the internal service is refreshed. On death of an
+ * existing IHealth service, the internal service is NOT cleared to avoid race condition between
+ * death notification and new service notification. Hence, a caller must check for transaction
+ * errors when calling into the service.
+ *
+ * @hide Should only be used internally.
+ */
+public abstract class HealthServiceWrapper {
+ /** @return the handler thread. Exposed for testing. */
+ @VisibleForTesting
+ abstract HandlerThread getHandlerThread();
+
+ /**
+ * Calls into get*() functions in the health HAL. This reads into the kernel interfaces
+ * directly.
+ *
+ * @see IBatteryPropertiesRegistrar#getProperty
+ */
+ public abstract int getProperty(int id, BatteryProperty prop) throws RemoteException;
+
+ /**
+ * Calls update() in the health HAL.
+ *
+ * @see IBatteryPropertiesRegistrar#scheduleUpdate
+ */
+ public abstract void scheduleUpdate() throws RemoteException;
+
+ /**
+ * Calls into getHealthInfo() in the health HAL. This returns a cached value in the health HAL
+ * implementation.
+ *
+ * @return health info. {@code null} if no health HAL service. {@code null} if any
+ * service-specific error when calling {@code getHealthInfo}, e.g. it is unsupported.
+ * @throws RemoteException for any transaction-level errors
+ */
+ public abstract android.hardware.health.HealthInfo getHealthInfo() throws RemoteException;
+
+ /**
+ * Create a new HealthServiceWrapper instance.
+ *
+ * @param healthInfoCallback the callback to call when health info changes
+ * @return the new HealthServiceWrapper instance, which may be backed by HIDL or AIDL service.
+ * @throws RemoteException transaction errors
+ * @throws NoSuchElementException no HIDL or AIDL service is available
+ */
+ public static HealthServiceWrapper create(@Nullable HealthInfoCallback healthInfoCallback)
+ throws RemoteException, NoSuchElementException {
+ return create(
+ healthInfoCallback == null ? null : new HealthHalCallbackHidl(healthInfoCallback),
+ new HealthServiceWrapperHidl.IServiceManagerSupplier() {},
+ new HealthServiceWrapperHidl.IHealthSupplier() {});
+ }
+
+ /**
+ * Create a new HealthServiceWrapper instance for testing.
+ *
+ * @param hidlRegCallback callback for HIDL service registration, or {@code null} if the client
+ * does not care about HIDL service registration notifications
+ * @param hidlServiceManagerSupplier supplier of HIDL service manager
+ * @param hidlHealthSupplier supplier of HIDL health HAL
+ * @return the new HealthServiceWrapper instance, which may be backed by HIDL or AIDL service.
+ */
+ @VisibleForTesting
+ static @NonNull HealthServiceWrapper create(
+ @Nullable HealthServiceWrapperHidl.Callback hidlRegCallback,
+ @NonNull HealthServiceWrapperHidl.IServiceManagerSupplier hidlServiceManagerSupplier,
+ @NonNull HealthServiceWrapperHidl.IHealthSupplier hidlHealthSupplier)
+ throws RemoteException, NoSuchElementException {
+ return new HealthServiceWrapperHidl(
+ hidlRegCallback, hidlServiceManagerSupplier, hidlHealthSupplier);
+ }
+}
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java b/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java
new file mode 100644
index 0000000..0301174
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.health;
+
+import static android.hardware.health.Translate.h2aTranslate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.health.HealthInfo;
+import android.hardware.health.V2_0.IHealth;
+import android.hardware.health.V2_0.Result;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.BatteryManager;
+import android.os.BatteryProperty;
+import android.os.HandlerThread;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.MutableInt;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Implement {@link HealthServiceWrapper} backed by the HIDL HAL.
+ *
+ * @hide
+ */
+final class HealthServiceWrapperHidl extends HealthServiceWrapper {
+ private static final String TAG = "HealthServiceWrapperHidl";
+ public static final String INSTANCE_VENDOR = "default";
+
+ private final IServiceNotification mNotification = new Notification();
+ private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder");
+ // These variables are fixed after init.
+ private Callback mCallback;
+ private IHealthSupplier mHealthSupplier;
+ private String mInstanceName;
+
+ // Last IHealth service received.
+ private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
+
+ private static void traceBegin(String name) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+ }
+
+ private static void traceEnd() {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ @Override
+ public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
+ traceBegin("HealthGetProperty");
+ try {
+ IHealth service = mLastService.get();
+ if (service == null) throw new RemoteException("no health service");
+ final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
+ switch (id) {
+ case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
+ service.getChargeCounter(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
+ service.getCurrentNow(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
+ service.getCurrentAverage(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CAPACITY:
+ service.getCapacity(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_STATUS:
+ service.getChargeStatus(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
+ service.getEnergyCounter(
+ (int result, long value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ }
+ return outResult.value;
+ } finally {
+ traceEnd();
+ }
+ }
+
+ @Override
+ public void scheduleUpdate() throws RemoteException {
+ getHandlerThread()
+ .getThreadHandler()
+ .post(
+ () -> {
+ traceBegin("HealthScheduleUpdate");
+ try {
+ IHealth service = mLastService.get();
+ if (service == null) {
+ Slog.e(TAG, "no health service");
+ return;
+ }
+ service.update();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Cannot call update on health HAL", ex);
+ } finally {
+ traceEnd();
+ }
+ });
+ }
+
+ private static class Mutable<T> {
+ public T value;
+ }
+
+ @Override
+ public HealthInfo getHealthInfo() throws RemoteException {
+ IHealth service = mLastService.get();
+ if (service == null) return null;
+ final Mutable<HealthInfo> ret = new Mutable<>();
+ service.getHealthInfo(
+ (result, value) -> {
+ if (result == Result.SUCCESS) {
+ ret.value = h2aTranslate(value.legacy);
+ }
+ });
+ return ret.value;
+ }
+
+ /**
+ * Start monitoring registration of new IHealth services. Only instance {@link #INSTANCE_VENDOR}
+ * and in device / framework manifest are used. This function should only be called once.
+ *
+ * <p>mCallback.onRegistration() is called synchronously (aka in init thread) before this method
+ * returns if callback is not null.
+ *
+ * @throws RemoteException transaction error when talking to IServiceManager
+ * @throws NoSuchElementException if one of the following cases: - No service manager; - {@link
+ * #INSTANCE_VENDOR} is not in manifests (i.e. not available on this device), or none of
+ * these instances are available to current process.
+ * @throws NullPointerException when supplier is null
+ */
+ @VisibleForTesting
+ HealthServiceWrapperHidl(
+ @Nullable Callback callback,
+ @NonNull IServiceManagerSupplier managerSupplier,
+ @NonNull IHealthSupplier healthSupplier)
+ throws RemoteException, NoSuchElementException, NullPointerException {
+ if (managerSupplier == null || healthSupplier == null) {
+ throw new NullPointerException();
+ }
+ mHealthSupplier = healthSupplier;
+
+ // Initialize mLastService and call callback for the first time (in init thread)
+ IHealth newService = null;
+ traceBegin("HealthInitGetService_" + INSTANCE_VENDOR);
+ try {
+ newService = healthSupplier.get(INSTANCE_VENDOR);
+ } catch (NoSuchElementException ex) {
+ /* ignored, handled below */
+ } finally {
+ traceEnd();
+ }
+ if (newService != null) {
+ mInstanceName = INSTANCE_VENDOR;
+ mLastService.set(newService);
+ }
+
+ if (mInstanceName == null || newService == null) {
+ throw new NoSuchElementException(
+ String.format(
+ "IHealth service instance %s isn't available. Perhaps no permission?",
+ INSTANCE_VENDOR));
+ }
+
+ if (callback != null) {
+ mCallback = callback;
+ mCallback.onRegistration(null, newService, mInstanceName);
+ }
+
+ // Register for future service registrations
+ traceBegin("HealthInitRegisterNotification");
+ mHandlerThread.start();
+ try {
+ managerSupplier
+ .get()
+ .registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);
+ } finally {
+ traceEnd();
+ }
+ Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
+ }
+
+ @VisibleForTesting
+ public HandlerThread getHandlerThread() {
+ return mHandlerThread;
+ }
+
+ /** Service registration callback. */
+ interface Callback {
+ /**
+ * This function is invoked asynchronously when a new and related IServiceNotification is
+ * received.
+ *
+ * @param service the recently retrieved service from IServiceManager. Can be a dead service
+ * before service notification of a new service is delivered. Implementation must handle
+ * cases for {@link RemoteException}s when calling into service.
+ * @param instance instance name.
+ */
+ void onRegistration(IHealth oldService, IHealth newService, String instance);
+ }
+
+ /**
+ * Supplier of services. Must not return null; throw {@link NoSuchElementException} if a service
+ * is not available.
+ */
+ interface IServiceManagerSupplier {
+ default IServiceManager get() throws NoSuchElementException, RemoteException {
+ return IServiceManager.getService();
+ }
+ }
+
+ /**
+ * Supplier of services. Must not return null; throw {@link NoSuchElementException} if a service
+ * is not available.
+ */
+ interface IHealthSupplier {
+ default IHealth get(String name) throws NoSuchElementException, RemoteException {
+ return IHealth.getService(name, true /* retry */);
+ }
+ }
+
+ private class Notification extends IServiceNotification.Stub {
+ @Override
+ public final void onRegistration(
+ String interfaceName, String instanceName, boolean preexisting) {
+ if (!IHealth.kInterfaceName.equals(interfaceName)) return;
+ if (!mInstanceName.equals(instanceName)) return;
+
+ // This runnable only runs on mHandlerThread and ordering is ensured, hence
+ // no locking is needed inside the runnable.
+ mHandlerThread
+ .getThreadHandler()
+ .post(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ IHealth newService = mHealthSupplier.get(mInstanceName);
+ IHealth oldService = mLastService.getAndSet(newService);
+
+ // preexisting may be inaccurate (race). Check for equality
+ // here.
+ if (Objects.equals(newService, oldService)) return;
+
+ Slog.i(
+ TAG,
+ "health: new instance registered " + mInstanceName);
+ // #init() may be called with null callback. Skip null
+ // callbacks.
+ if (mCallback == null) return;
+ mCallback.onRegistration(
+ oldService, newService, mInstanceName);
+ } catch (NoSuchElementException | RemoteException ex) {
+ Slog.e(
+ TAG,
+ "health: Cannot get instance '"
+ + mInstanceName
+ + "': "
+ + ex.getMessage()
+ + ". Perhaps no permission?");
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/health/Utils.java b/services/core/java/com/android/server/health/Utils.java
new file mode 100644
index 0000000..a8c978c
--- /dev/null
+++ b/services/core/java/com/android/server/health/Utils.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.health;
+
+/**
+ * Utils for {@link om.android.server.BatteryService} to deal with health info structs.
+ *
+ * @hide
+ */
+public class Utils {
+ private Utils() {}
+
+ /**
+ * Copy health info struct.
+ *
+ * @param dst destination
+ * @param src source
+ */
+ public static void copy(
+ android.hardware.health.V1_0.HealthInfo dst,
+ android.hardware.health.V1_0.HealthInfo src) {
+ dst.chargerAcOnline = src.chargerAcOnline;
+ dst.chargerUsbOnline = src.chargerUsbOnline;
+ dst.chargerWirelessOnline = src.chargerWirelessOnline;
+ dst.maxChargingCurrent = src.maxChargingCurrent;
+ dst.maxChargingVoltage = src.maxChargingVoltage;
+ dst.batteryStatus = src.batteryStatus;
+ dst.batteryHealth = src.batteryHealth;
+ dst.batteryPresent = src.batteryPresent;
+ dst.batteryLevel = src.batteryLevel;
+ dst.batteryVoltage = src.batteryVoltage;
+ dst.batteryTemperature = src.batteryTemperature;
+ dst.batteryCurrent = src.batteryCurrent;
+ dst.batteryCycleCount = src.batteryCycleCount;
+ dst.batteryFullCharge = src.batteryFullCharge;
+ dst.batteryChargeCounter = src.batteryChargeCounter;
+ dst.batteryTechnology = src.batteryTechnology;
+ }
+
+ /**
+ * Copy battery fields of {@link android.hardware.health.HealthInfo} V1. This excludes
+ * non-battery fields like {@link android.hardware.health.HealthInfo#diskStats diskStats} and
+ * {@link android.hardware.health.HealthInfo#storageInfos storageInfos}
+ *
+ * @param dst destination
+ * @param src source
+ */
+ public static void copyV1Battery(
+ android.hardware.health.HealthInfo dst, android.hardware.health.HealthInfo src) {
+ dst.chargerAcOnline = src.chargerAcOnline;
+ dst.chargerUsbOnline = src.chargerUsbOnline;
+ dst.chargerWirelessOnline = src.chargerWirelessOnline;
+ dst.maxChargingCurrentMicroamps = src.maxChargingCurrentMicroamps;
+ dst.maxChargingVoltageMicrovolts = src.maxChargingVoltageMicrovolts;
+ dst.batteryStatus = src.batteryStatus;
+ dst.batteryHealth = src.batteryHealth;
+ dst.batteryPresent = src.batteryPresent;
+ dst.batteryLevel = src.batteryLevel;
+ dst.batteryVoltageMillivolts = src.batteryVoltageMillivolts;
+ dst.batteryTemperatureTenthsCelsius = src.batteryTemperatureTenthsCelsius;
+ dst.batteryCurrentMicroamps = src.batteryCurrentMicroamps;
+ dst.batteryCycleCount = src.batteryCycleCount;
+ dst.batteryFullChargeUah = src.batteryFullChargeUah;
+ dst.batteryChargeCounterUah = src.batteryChargeCounterUah;
+ dst.batteryTechnology = src.batteryTechnology;
+ dst.batteryCurrentAverageMicroamps = src.batteryCurrentAverageMicroamps;
+ dst.batteryCapacityLevel = src.batteryCapacityLevel;
+ dst.batteryChargeTimeToFullNowSeconds = src.batteryChargeTimeToFullNowSeconds;
+ dst.batteryFullChargeDesignCapacityUah = src.batteryFullChargeDesignCapacityUah;
+ }
+}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 73de0f8..ffc1aed4 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -51,6 +51,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
class BluetoothRouteProvider {
private static final String TAG = "BTRouteProvider";
@@ -174,8 +175,9 @@
private void buildBluetoothRoutes() {
mBluetoothRoutes.clear();
- if (mBluetoothAdapter.getBondedDevices() != null) {
- for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices()) {
+ Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
+ if (bondedDevices != null) {
+ for (BluetoothDevice device : bondedDevices) {
if (device.isConnected()) {
BluetoothRouteInfo newBtRoute = createBluetoothRoute(device);
if (newBtRoute.connectedProfiles.size() > 0) {
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index 28ae6a4..a15fc3e 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -1,11 +1,7 @@
set noparent
-codewiz@google.com
-jchalard@google.com
+include platform/packages/modules/Connectivity:/OWNERS
+
jsharkey@android.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
sudheersai@google.com
yamasani@google.com
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 827dfc0..20bcc5e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21917,8 +21917,10 @@
ApexManager.ActiveApexInfo apexInfo) {
for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
ScanPartition sp = SYSTEM_PARTITIONS.get(i);
- if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.getFolder().getAbsolutePath())) {
+ if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
+ sp.getFolder().getAbsolutePath())
+ || apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
+ sp.getFolder().getAbsolutePath() + File.separator)) {
return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e408822..4a97720 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2666,6 +2666,24 @@
Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in"
+ " interceptKeyBeforeQueueing");
return key_consumed;
+ case KeyEvent.KEYCODE_VIDEO_APP_1:
+ case KeyEvent.KEYCODE_VIDEO_APP_2:
+ case KeyEvent.KEYCODE_VIDEO_APP_3:
+ case KeyEvent.KEYCODE_VIDEO_APP_4:
+ case KeyEvent.KEYCODE_VIDEO_APP_5:
+ case KeyEvent.KEYCODE_VIDEO_APP_6:
+ case KeyEvent.KEYCODE_VIDEO_APP_7:
+ case KeyEvent.KEYCODE_VIDEO_APP_8:
+ case KeyEvent.KEYCODE_FEATURED_APP_1:
+ case KeyEvent.KEYCODE_FEATURED_APP_2:
+ case KeyEvent.KEYCODE_FEATURED_APP_3:
+ case KeyEvent.KEYCODE_FEATURED_APP_4:
+ case KeyEvent.KEYCODE_DEMO_APP_1:
+ case KeyEvent.KEYCODE_DEMO_APP_2:
+ case KeyEvent.KEYCODE_DEMO_APP_3:
+ case KeyEvent.KEYCODE_DEMO_APP_4:
+ Slog.wtf(TAG, "KEYCODE_APP_X should be handled in interceptKeyBeforeQueueing");
+ return key_consumed;
case KeyEvent.KEYCODE_SYSRQ:
if (down && repeatCount == 0) {
mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
@@ -3773,6 +3791,26 @@
}
break;
}
+ case KeyEvent.KEYCODE_VIDEO_APP_1:
+ case KeyEvent.KEYCODE_VIDEO_APP_2:
+ case KeyEvent.KEYCODE_VIDEO_APP_3:
+ case KeyEvent.KEYCODE_VIDEO_APP_4:
+ case KeyEvent.KEYCODE_VIDEO_APP_5:
+ case KeyEvent.KEYCODE_VIDEO_APP_6:
+ case KeyEvent.KEYCODE_VIDEO_APP_7:
+ case KeyEvent.KEYCODE_VIDEO_APP_8:
+ case KeyEvent.KEYCODE_FEATURED_APP_1:
+ case KeyEvent.KEYCODE_FEATURED_APP_2:
+ case KeyEvent.KEYCODE_FEATURED_APP_3:
+ case KeyEvent.KEYCODE_FEATURED_APP_4:
+ case KeyEvent.KEYCODE_DEMO_APP_1:
+ case KeyEvent.KEYCODE_DEMO_APP_2:
+ case KeyEvent.KEYCODE_DEMO_APP_3:
+ case KeyEvent.KEYCODE_DEMO_APP_4: {
+ // Just drop if keys are not intercepted for direct key.
+ result &= ~ACTION_PASS_TO_USER;
+ break;
+ }
}
// Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 68b760a..1ef2025 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -92,7 +92,6 @@
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.health.V2_0.IHealth;
import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
@@ -190,13 +189,13 @@
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.role.RoleManagerLocal;
-import com.android.server.BatteryService;
import com.android.server.BinderCallsStatsService;
import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.health.HealthServiceWrapper;
import com.android.server.notification.NotificationManagerService;
import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
@@ -226,6 +225,7 @@
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
+import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
@@ -354,7 +354,7 @@
private File mBaseDir;
@GuardedBy("mHealthHalLock")
- private BatteryService.HealthServiceWrapper mHealthService;
+ private HealthServiceWrapper mHealthService;
@Nullable
@GuardedBy("mCpuTimePerThreadFreqLock")
@@ -799,10 +799,9 @@
KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext);
// Initialize HealthService
- mHealthService = new BatteryService.HealthServiceWrapper();
try {
- mHealthService.init();
- } catch (RemoteException e) {
+ mHealthService = HealthServiceWrapper.create(null);
+ } catch (RemoteException | NoSuchElementException e) {
Slog.e(TAG, "failed to initialize healthHalWrapper");
}
@@ -3975,38 +3974,40 @@
}
int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) {
- IHealth healthService = mHealthService.getLastService();
- if (healthService == null) {
+ if (mHealthService == null) {
return StatsManager.PULL_SKIP;
}
+ android.hardware.health.HealthInfo healthInfo;
try {
- healthService.getHealthInfo((result, value) -> {
- int pulledValue;
- switch(atomTag) {
- case FrameworkStatsLog.BATTERY_LEVEL:
- pulledValue = value.legacy.batteryLevel;
- break;
- case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY:
- pulledValue = value.legacy.batteryChargeCounter;
- break;
- case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
- pulledValue = value.legacy.batteryFullCharge;
- break;
- case FrameworkStatsLog.BATTERY_VOLTAGE:
- pulledValue = value.legacy.batteryVoltage;
- break;
- case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
- pulledValue = value.legacy.batteryCycleCount;
- break;
- default:
- throw new IllegalStateException("Invalid atomTag in healthHal puller: "
- + atomTag);
- }
- pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue));
- });
+ healthInfo = mHealthService.getHealthInfo();
} catch (RemoteException | IllegalStateException e) {
return StatsManager.PULL_SKIP;
}
+ if (healthInfo == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ int pulledValue;
+ switch (atomTag) {
+ case FrameworkStatsLog.BATTERY_LEVEL:
+ pulledValue = healthInfo.batteryLevel;
+ break;
+ case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY:
+ pulledValue = healthInfo.batteryChargeCounterUah;
+ break;
+ case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
+ pulledValue = healthInfo.batteryFullChargeUah;
+ break;
+ case FrameworkStatsLog.BATTERY_VOLTAGE:
+ pulledValue = healthInfo.batteryVoltageMillivolts;
+ break;
+ case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
+ pulledValue = healthInfo.batteryCycleCount;
+ break;
+ default:
+ return StatsManager.PULL_SKIP;
+ }
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue));
return StatsManager.PULL_SUCCESS;
}
diff --git a/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java b/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
index 4eb1b99..60068cb 100644
--- a/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
+++ b/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
@@ -25,6 +25,7 @@
import java.time.Duration;
import java.util.ArrayDeque;
+import java.util.Iterator;
/**
* A class that behaves like the following definition, except it stores the history of values set
@@ -112,9 +113,11 @@
if (mValues == null) {
ipw.println("{Empty}");
} else {
- int i = mSetCount;
- for (TimestampedValue<V> valueHolder : mValues) {
- ipw.print(--i);
+ int i = mSetCount - mValues.size();
+ Iterator<TimestampedValue<V>> reverseIterator = mValues.descendingIterator();
+ while (reverseIterator.hasNext()) {
+ TimestampedValue<V> valueHolder = reverseIterator.next();
+ ipw.print(i++);
ipw.print("@");
ipw.print(Duration.ofMillis(valueHolder.getReferenceTimeMillis()).toString());
ipw.print(": ");
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 2894708..b9ceec1 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -315,6 +315,7 @@
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
List<TvInputInfo> inputList = new ArrayList<>();
+ List<ComponentName> hardwareComponents = new ArrayList<>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
@@ -325,6 +326,7 @@
ComponentName component = new ComponentName(si.packageName, si.name);
if (hasHardwarePermission(pm, component)) {
+ hardwareComponents.add(component);
ServiceState serviceState = userState.serviceStateMap.get(component);
if (serviceState == null) {
// New hardware input found. Create a new ServiceState and connect to the
@@ -397,6 +399,15 @@
}
}
+ // Clean up ServiceState corresponding to the removed hardware inputs
+ Iterator<ServiceState> it = userState.serviceStateMap.values().iterator();
+ while (it.hasNext()) {
+ ServiceState serviceState = it.next();
+ if (serviceState.isHardware && !hardwareComponents.contains(serviceState.component)) {
+ it.remove();
+ }
+ }
+
userState.inputMap.clear();
userState.inputMap = inputMap;
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 239a916..1c46ac8 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -98,6 +98,7 @@
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
+import java.net.NetworkInterface;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -2048,7 +2049,8 @@
return builder.build();
}
- private static LinkProperties buildConnectedLinkProperties(
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ LinkProperties buildConnectedLinkProperties(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig,
@@ -2076,6 +2078,13 @@
lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes());
underlyingMtu = underlyingLp.getMtu();
+
+ // WiFi LinkProperties uses DHCP as the sole source of MTU information, and as a result
+ // often lists MTU as 0 (see b/184678973). Use the interface MTU as retrieved by
+ // NetworkInterface APIs.
+ if (underlyingMtu == 0 && underlyingLp.getInterfaceName() != null) {
+ underlyingMtu = mDeps.getUnderlyingIfaceMtu(underlyingLp.getInterfaceName());
+ }
} else {
Slog.wtf(
TAG,
@@ -2417,6 +2426,17 @@
public long getElapsedRealTime() {
return SystemClock.elapsedRealtime();
}
+
+ /** Gets the MTU for the given underlying interface. */
+ public int getUnderlyingIfaceMtu(String ifaceName) {
+ try {
+ final NetworkInterface underlyingIface = NetworkInterface.getByName(ifaceName);
+ return underlyingIface == null ? 0 : underlyingIface.getMTU();
+ } catch (IOException e) {
+ Slog.d(TAG, "Could not get MTU of underlying network", e);
+ return 0;
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 26c04f9..d1f2177 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -140,6 +140,7 @@
import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING;
+import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO;
import static com.android.server.wm.ActivityRecordProto.NAME;
import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS;
import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS;
@@ -8672,6 +8673,7 @@
}
proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
+ proto.write(MIN_ASPECT_RATIO, info.getMinAspectRatio());
}
@Override
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index fe1020c..a7216da 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -190,8 +190,7 @@
if (keyguardChanged) {
// Irrelevant to AOD.
- dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */,
- false /* turningScreenOn */);
+ dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */);
mKeyguardGoingAway = false;
if (keyguardShowing) {
mDismissalRequested = false;
@@ -385,6 +384,8 @@
mService.continueWindowLayout();
}
}
+ dismissMultiWindowModeForTaskIfNeeded(topActivity != null
+ ? topActivity.getRootTask() : null);
}
/**
@@ -410,21 +411,6 @@
}
}
- /**
- * Called when somebody wants to turn screen on.
- */
- private void handleTurnScreenOn(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
-
- mTaskSupervisor.wakeUp("handleTurnScreenOn");
- if (mKeyguardShowing && canDismissKeyguard()) {
- mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
- mDismissalRequested = true;
- }
- }
-
boolean isDisplayOccluded(int displayId) {
return getDisplayState(displayId).mOccluded;
}
@@ -438,11 +424,9 @@
}
private void dismissMultiWindowModeForTaskIfNeeded(
- @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) {
- // If turningScreenOn is true, it means that the visibility state has changed from
- // currentTaskControllingOcclusion and we should update windowing mode.
+ @Nullable Task currentTaskControllingOcclusion) {
// TODO(b/113840485): Handle docked stack for individual display.
- if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) {
+ if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) {
return;
}
@@ -581,26 +565,17 @@
&& controller.mWindowManager.isKeyguardSecure(
controller.mService.getCurrentUserId());
- boolean occludingChange = false;
- boolean turningScreenOn = false;
if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
&& mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity
- || controller.canDismissKeyguard())) {
- turningScreenOn = true;
- controller.handleTurnScreenOn(mDisplayId);
+ && (mRequestDismissKeyguard || occludedByActivity)) {
+ controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
- occludingChange = true;
controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
}
-
- if (occludingChange || turningScreenOn) {
- controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn);
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9caef70..3421b28 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -167,8 +167,10 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
-import android.hardware.configstore.V1_0.ISurfaceFlingerConfigs;
import android.hardware.configstore.V1_0.OptionalBool;
+import android.hardware.configstore.V1_1.DisplayOrientation;
+import android.hardware.configstore.V1_1.ISurfaceFlingerConfigs;
+import android.hardware.configstore.V1_1.OptionalDisplayOrientation;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManager;
@@ -220,6 +222,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import android.view.Display;
+import android.view.DisplayAddress;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -465,6 +468,8 @@
*/
static final boolean ENABLE_FIXED_ROTATION_TRANSFORM =
SystemProperties.getBoolean("persist.wm.fixed_rotation_transform", true);
+ private @Surface.Rotation int mPrimaryDisplayOrientation = Surface.ROTATION_0;
+ private DisplayAddress mPrimaryDisplayPhysicalAddress;
// Enums for animation scale update types.
@Retention(RetentionPolicy.SOURCE)
@@ -2461,16 +2466,21 @@
configChanged = displayContent.updateOrientation();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- final DisplayInfo rotatedDisplayInfo =
- win.mToken.getFixedRotationTransformDisplayInfo();
- if (rotatedDisplayInfo != null) {
- outSurfaceControl.setTransformHint(rotatedDisplayInfo.rotation);
- } else {
- // We have to update the transform hint of display here, but we need to get if from
- // SurfaceFlinger, so set it as rotation of display for most cases, then
- // SurfaceFlinger would still update the transform hint of display in next frame.
- outSurfaceControl.setTransformHint(displayContent.getDisplayInfo().rotation);
+ final DisplayInfo displayInfo = win.getDisplayInfo();
+ int transformHint = displayInfo.rotation;
+ // If the window is on the primary display, use the panel orientation to adjust the
+ // transform hint
+ final boolean isPrimaryDisplay = displayInfo.address != null &&
+ displayInfo.address.equals(mPrimaryDisplayPhysicalAddress);
+ if (isPrimaryDisplay) {
+ transformHint = (transformHint + mPrimaryDisplayOrientation) % 4;
}
+ outSurfaceControl.setTransformHint(transformHint);
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "Passing transform hint %d for window %s%s",
+ transformHint, win,
+ isPrimaryDisplay ? " on primary display with orientation "
+ + mPrimaryDisplayOrientation : "");
if (toBeDisplayed && win.mIsWallpaper) {
displayContent.mWallpaperController.updateWallpaperOffset(win, false /* sync */);
@@ -4868,6 +4878,9 @@
mTaskSnapshotController.systemReady();
mHasWideColorGamutSupport = queryWideColorGamutSupport();
mHasHdrSupport = queryHdrSupport();
+ mPrimaryDisplayOrientation = queryPrimaryDisplayOrientation();
+ mPrimaryDisplayPhysicalAddress =
+ DisplayAddress.fromPhysicalDisplayId(SurfaceControl.getPrimaryPhysicalDisplayId());
UiThread.getHandler().post(mSettingsObserver::loadSettings);
IVrManager vrManager = IVrManager.Stub.asInterface(
ServiceManager.getService(Context.VR_SERVICE));
@@ -4887,6 +4900,9 @@
}
}
+
+ // Keep logic in sync with SurfaceFlingerProperties.cpp
+ // Consider exposing properties via ISurfaceComposer instead.
private static boolean queryWideColorGamutSupport() {
boolean defaultValue = false;
Optional<Boolean> hasWideColorProp = SurfaceFlingerProperties.has_wide_color_display();
@@ -4927,6 +4943,39 @@
return false;
}
+ private static @Surface.Rotation int queryPrimaryDisplayOrientation() {
+ Optional<SurfaceFlingerProperties.primary_display_orientation_values> prop =
+ SurfaceFlingerProperties.primary_display_orientation();
+ if (prop.isPresent()) {
+ switch (prop.get()) {
+ case ORIENTATION_90: return Surface.ROTATION_90;
+ case ORIENTATION_180: return Surface.ROTATION_180;
+ case ORIENTATION_270: return Surface.ROTATION_270;
+ case ORIENTATION_0:
+ default:
+ return Surface.ROTATION_0;
+ }
+ }
+ try {
+ ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService();
+ OptionalDisplayOrientation primaryDisplayOrientation =
+ surfaceFlinger.primaryDisplayOrientation();
+ if (primaryDisplayOrientation != null && primaryDisplayOrientation.specified) {
+ switch (primaryDisplayOrientation.value) {
+ case DisplayOrientation.ORIENTATION_90: return Surface.ROTATION_90;
+ case DisplayOrientation.ORIENTATION_180: return Surface.ROTATION_180;
+ case DisplayOrientation.ORIENTATION_270: return Surface.ROTATION_270;
+ case DisplayOrientation.ORIENTATION_0:
+ default:
+ return Surface.ROTATION_0;
+ }
+ }
+ } catch (Exception e) {
+ // Use default value if we can't talk to config store.
+ }
+ return Surface.ROTATION_0;
+ }
+
void reportFocusChanged(IBinder oldToken, IBinder newToken) {
WindowState lastFocus;
WindowState newFocus;
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index 3a9b2dc..cb52e5f 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -19,6 +19,7 @@
import static java.util.stream.Collectors.toMap;
import android.Manifest;
+import android.content.ComponentName;
import android.content.Context;
import android.os.ISystemConfig;
import android.util.ArrayMap;
@@ -87,14 +88,14 @@
}
@Override
- public List<String> getEnabledComponentOverrides(String packageName) {
+ public List<ComponentName> getEnabledComponentOverrides(String packageName) {
ArrayMap<String, Boolean> systemComponents = SystemConfig.getInstance()
.getComponentsEnabledStates(packageName);
- List<String> enabledComponent = new ArrayList<>();
+ List<ComponentName> enabledComponent = new ArrayList<>();
if (systemComponents != null) {
for (Map.Entry<String, Boolean> entry : systemComponents.entrySet()) {
if (Boolean.TRUE.equals(entry.getValue())) {
- enabledComponent.add(entry.getKey());
+ enabledComponent.add(new ComponentName(packageName, entry.getKey()));
}
}
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index fdf23d3..8369319 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -23,7 +23,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.IBinder.DeathRecipient;
import android.os.Looper;
@@ -32,12 +31,11 @@
import android.os.SystemProperties;
import android.os.UpdateEngine;
import android.os.UpdateEngineCallback;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.DeviceConfig;
import android.util.Log;
import com.android.internal.R;
+import com.android.internal.os.BackgroundThread;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -45,9 +43,6 @@
import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
import com.android.server.wm.ActivityTaskManagerInternal;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@@ -152,7 +147,7 @@
connectNativeService();
break;
default:
- throw new AssertionError("Unknown message: " + message.toString());
+ throw new AssertionError("Unknown message: " + message);
}
}
}
@@ -196,11 +191,14 @@
Log.d(LOG_TAG, "Starting background process job");
}
- try {
- sSelfService.mIProfcollect.process(false);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
- }
+ BackgroundThread.get().getThreadHandler().post(
+ () -> {
+ try {
+ sSelfService.mIProfcollect.process();
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ }
+ });
return true;
}
@@ -306,79 +304,27 @@
return;
}
- if (!getUploaderEnabledConfig(getContext())) {
- return;
- }
-
- new Thread(() -> {
+ Context context = getContext();
+ BackgroundThread.get().getThreadHandler().post(() -> {
try {
- Context context = getContext();
- final String uploaderPkg = getUploaderPackageName(context);
- final String uploaderAction = getUploaderActionName(context);
- String reportUuid = mIProfcollect.report();
+ // Prepare profile report
+ String reportName = mIProfcollect.report() + ".zip";
- final int profileId = getBBProfileId();
- String reportDir = "/data/user/" + profileId
- + "/com.google.android.apps.internal.betterbug/cache/";
- String reportPath = reportDir + reportUuid + ".zip";
-
- if (!Files.exists(Paths.get(reportDir))) {
- Log.i(LOG_TAG, "Destination directory does not exist, abort upload.");
+ if (!context.getResources().getBoolean(
+ R.bool.config_profcollectReportUploaderEnabled)) {
+ Log.i(LOG_TAG, "Upload is not enabled.");
return;
}
- Intent uploadIntent =
- new Intent(uploaderAction)
- .setPackage(uploaderPkg)
- .putExtra("EXTRA_DESTINATION", "PROFCOLLECT")
- .putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName())
- .putExtra("EXTRA_PROFILE_PATH", reportPath)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-
- List<ResolveInfo> receivers =
- context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0);
- if (receivers == null || receivers.isEmpty()) {
- Log.i(LOG_TAG, "No one to receive upload intent, abort upload.");
- return;
- }
- mIProfcollect.copy_report_to_bb(profileId, reportUuid);
- context.sendBroadcast(uploadIntent);
- mIProfcollect.delete_report(reportUuid);
+ // Upload the report
+ Intent intent = new Intent()
+ .setPackage("com.android.shell")
+ .setAction("com.android.shell.action.PROFCOLLECT_UPLOAD")
+ .putExtra("filename", reportName);
+ context.sendBroadcast(intent);
} catch (RemoteException e) {
Log.e(LOG_TAG, e.getMessage());
}
- }).start();
- }
-
- /**
- * Get BetterBug's profile ID. It is the work profile ID, if it exists. Otherwise the system
- * user ID.
- *
- * @return BetterBug's profile ID.
- */
- private int getBBProfileId() {
- UserManager userManager = UserManager.get(getContext());
- int[] profiles = userManager.getProfileIds(UserHandle.USER_SYSTEM, false);
- for (int p : profiles) {
- if (userManager.getUserInfo(p).isManagedProfile()) {
- return p;
- }
- }
- return UserHandle.USER_SYSTEM;
- }
-
- private boolean getUploaderEnabledConfig(Context context) {
- return context.getResources().getBoolean(
- R.bool.config_profcollectReportUploaderEnabled);
- }
-
- private String getUploaderPackageName(Context context) {
- return context.getResources().getString(
- R.string.config_defaultProfcollectReportUploaderApp);
- }
-
- private String getUploaderActionName(Context context) {
- return context.getResources().getString(
- R.string.config_defaultProfcollectReportUploaderAction);
+ });
}
}
diff --git a/services/tests/mockingservicestests/OWNERS b/services/tests/mockingservicestests/OWNERS
new file mode 100644
index 0000000..0fb0c30
--- /dev/null
+++ b/services/tests/mockingservicestests/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
diff --git a/services/tests/servicestests/OWNERS b/services/tests/servicestests/OWNERS
new file mode 100644
index 0000000..0fb0c30
--- /dev/null
+++ b/services/tests/servicestests/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
deleted file mode 100644
index a2ecbc3..0000000
--- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static junit.framework.Assert.*;
-
-import static org.mockito.Mockito.*;
-
-import android.hardware.health.V2_0.IHealth;
-import android.hidl.manager.V1_0.IServiceManager;
-import android.hidl.manager.V1_0.IServiceNotification;
-import android.test.AndroidTestCase;
-
-import androidx.test.filters.SmallTest;
-
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.NoSuchElementException;
-
-public class BatteryServiceTest extends AndroidTestCase {
-
- @Mock IServiceManager mMockedManager;
- @Mock IHealth mMockedHal;
- @Mock IHealth mMockedHal2;
-
- @Mock BatteryService.HealthServiceWrapper.Callback mCallback;
- @Mock BatteryService.HealthServiceWrapper.IServiceManagerSupplier mManagerSupplier;
- @Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier;
- BatteryService.HealthServiceWrapper mWrapper;
-
- private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR;
-
- @Override
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Override
- public void tearDown() {
- if (mWrapper != null)
- mWrapper.getHandlerThread().quitSafely();
- }
-
- public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
- return new ArgumentMatcher<T>() {
- @Override public boolean matches(T e) {
- return collection.contains(e);
- }
- @Override public String toString() {
- return collection.toString();
- }
- };
- }
-
- private void initForInstances(String... instanceNamesArr) throws Exception {
- final Collection<String> instanceNames = Arrays.asList(instanceNamesArr);
- doAnswer((invocation) -> {
- // technically, preexisting is ignored by
- // BatteryService.HealthServiceWrapper.Notification, but still call it correctly.
- sendNotification(invocation, true);
- sendNotification(invocation, true);
- sendNotification(invocation, false);
- return null;
- }).when(mMockedManager).registerForNotifications(
- eq(IHealth.kInterfaceName),
- argThat(isOneOf(instanceNames)),
- any(IServiceNotification.class));
-
- doReturn(mMockedManager).when(mManagerSupplier).get();
- doReturn(mMockedHal) // init calls this
- .doReturn(mMockedHal) // notification 1
- .doReturn(mMockedHal) // notification 2
- .doReturn(mMockedHal2) // notification 3
- .doThrow(new RuntimeException("Should not call getService for more than 4 times"))
- .when(mHealthServiceSupplier).get(argThat(isOneOf(instanceNames)));
-
- mWrapper = new BatteryService.HealthServiceWrapper();
- }
-
- private void waitHandlerThreadFinish() throws Exception {
- for (int i = 0; i < 5; i++) {
- if (!mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks()) {
- return;
- }
- Thread.sleep(300);
- }
- assertFalse(mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks());
- }
-
- private static void sendNotification(InvocationOnMock invocation, boolean preexisting)
- throws Exception {
- ((IServiceNotification)invocation.getArguments()[2]).onRegistration(
- IHealth.kInterfaceName,
- (String)invocation.getArguments()[1],
- preexisting);
- }
-
- @SmallTest
- public void testWrapPreferVendor() throws Exception {
- initForInstances(VENDOR);
- mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- waitHandlerThreadFinish();
- verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
- verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
- verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(VENDOR));
- }
-
- @SmallTest
- public void testNoService() throws Exception {
- initForInstances("unrelated");
- try {
- mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- fail("Expect NoSuchElementException");
- } catch (NoSuchElementException ex) {
- // expected
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index 5c53d43..9e1445c 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -26,11 +26,11 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.AudioSystem;
+import android.media.BtProfileConnectionInfo;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -98,16 +98,12 @@
Log.i(TAG, "starting testPostA2dpDeviceConnectionChange");
Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
- mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1));
+ mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
+ BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource"));
Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS);
- verify(mSpyDevInventory, times(1)).setBluetoothA2dpDeviceConnectionState(
- any(BluetoothDevice.class),
- ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED) /*state*/,
- ArgumentMatchers.eq(BluetoothProfile.A2DP) /*profile*/,
- ArgumentMatchers.eq(true) /*suppressNoisyIntent*/, anyInt() /*musicDevice*/,
- ArgumentMatchers.eq(1) /*a2dpVolume*/
+ verify(mSpyDevInventory, times(1)).setBluetoothActiveDevice(
+ any(AudioDeviceBroker.BtDeviceInfo.class)
);
// verify the connection was reported to AudioSystem
@@ -210,30 +206,29 @@
((NoOpAudioSystemAdapter) mSpyAudioSystem).configureIsStreamActive(mockMediaPlayback);
// first connection: ensure the device is connected as a starting condition for the test
- mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1));
+ mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
+ BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource"));
Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
// disconnection
- mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
- BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1));
+ mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(null, mFakeBtDevice,
+ BtProfileConnectionInfo.a2dpInfo(false, -1), "testSource"));
if (delayAfterDisconnection > 0) {
Thread.sleep(delayAfterDisconnection);
}
// reconnection
- mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2));
+ mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
+ BtProfileConnectionInfo.a2dpInfo(true, 2), "testSource"));
Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS);
// Verify disconnection has been cancelled and we're seeing two connections attempts,
// with the device connected at the end of the test
- verify(mSpyDevInventory, times(2)).onSetA2dpSinkConnectionState(
- any(BtHelper.BluetoothA2dpDeviceInfo.class),
- ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED));
+ verify(mSpyDevInventory, times(2)).onSetBtActiveDevice(
+ any(AudioDeviceBroker.BtDeviceInfo.class), anyInt());
Assert.assertTrue("Mock device not connected",
mSpyDevInventory.isA2dpDeviceConnected(mFakeBtDevice));
diff --git a/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java
new file mode 100644
index 0000000..c97a67b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.health;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.Mockito.*;
+
+import android.hardware.health.V2_0.IHealth;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.RemoteException;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+@RunWith(AndroidJUnit4.class)
+public class HealthServiceWrapperTest {
+
+ @Mock IServiceManager mMockedManager;
+ @Mock IHealth mMockedHal;
+ @Mock IHealth mMockedHal2;
+
+ @Mock HealthServiceWrapperHidl.Callback mCallback;
+ @Mock HealthServiceWrapperHidl.IServiceManagerSupplier mManagerSupplier;
+ @Mock HealthServiceWrapperHidl.IHealthSupplier mHealthServiceSupplier;
+ HealthServiceWrapper mWrapper;
+
+ private static final String VENDOR = HealthServiceWrapperHidl.INSTANCE_VENDOR;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @After
+ public void tearDown() {
+ if (mWrapper != null) mWrapper.getHandlerThread().quitSafely();
+ }
+
+ public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
+ return new ArgumentMatcher<T>() {
+ @Override
+ public boolean matches(T e) {
+ return collection.contains(e);
+ }
+
+ @Override
+ public String toString() {
+ return collection.toString();
+ }
+ };
+ }
+
+ private void initForInstances(String... instanceNamesArr) throws Exception {
+ final Collection<String> instanceNames = Arrays.asList(instanceNamesArr);
+ doAnswer(
+ (invocation) -> {
+ // technically, preexisting is ignored by
+ // HealthServiceWrapperHidl.Notification, but still call it correctly.
+ sendNotification(invocation, true);
+ sendNotification(invocation, true);
+ sendNotification(invocation, false);
+ return null;
+ })
+ .when(mMockedManager)
+ .registerForNotifications(
+ eq(IHealth.kInterfaceName),
+ argThat(isOneOf(instanceNames)),
+ any(IServiceNotification.class));
+
+ doReturn(mMockedManager).when(mManagerSupplier).get();
+ doReturn(mMockedHal) // init calls this
+ .doReturn(mMockedHal) // notification 1
+ .doReturn(mMockedHal) // notification 2
+ .doReturn(mMockedHal2) // notification 3
+ .doThrow(new RuntimeException("Should not call getService for more than 4 times"))
+ .when(mHealthServiceSupplier)
+ .get(argThat(isOneOf(instanceNames)));
+ }
+
+ private void waitHandlerThreadFinish() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ if (!mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks()) {
+ return;
+ }
+ Thread.sleep(300);
+ }
+ assertFalse(mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks());
+ }
+
+ private static void sendNotification(InvocationOnMock invocation, boolean preexisting)
+ throws Exception {
+ ((IServiceNotification) invocation.getArguments()[2])
+ .onRegistration(
+ IHealth.kInterfaceName, (String) invocation.getArguments()[1], preexisting);
+ }
+
+ private void createWrapper() throws RemoteException {
+ mWrapper = HealthServiceWrapper.create(mCallback, mManagerSupplier, mHealthServiceSupplier);
+ }
+
+ @SmallTest
+ @Test
+ public void testWrapPreferVendor() throws Exception {
+ initForInstances(VENDOR);
+ createWrapper();
+ waitHandlerThreadFinish();
+ verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
+ verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
+ verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(VENDOR));
+ }
+
+ @SmallTest
+ @Test
+ public void testNoService() throws Exception {
+ initForInstances("unrelated");
+ try {
+ createWrapper();
+ fail("Expect NoSuchElementException");
+ } catch (NoSuchElementException ex) {
+ // expected
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/health/OWNERS b/services/tests/servicestests/src/com/android/server/health/OWNERS
new file mode 100644
index 0000000..81522fc
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/health/OWNERS
@@ -0,0 +1 @@
+file:platform/hardware/interfaces:/health/aidl/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java b/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java
index ce72499..d5d2cbd 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java
@@ -17,17 +17,19 @@
package com.android.server.timedetector;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.util.IndentingPrintWriter;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.server.timezonedetector.ReferenceWithHistory;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.StringWriter;
+import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
public class ReferenceWithHistoryTest {
@@ -41,31 +43,34 @@
// Check unset behavior.
compareGet(referenceWithHistory, reference, null);
- assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+ assertDumpContent(referenceWithHistory);
compareToString(referenceWithHistory, reference, "null");
// Try setting null.
setAndCompareReturnValue(referenceWithHistory, reference, null);
compareGet(referenceWithHistory, reference, null);
- assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+ assertDumpContent(referenceWithHistory, new DumpLine(0, "null"));
compareToString(referenceWithHistory, reference, "null");
// Try setting a non-null value.
setAndCompareReturnValue(referenceWithHistory, reference, "Foo");
compareGet(referenceWithHistory, reference, "Foo");
- assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+ assertDumpContent(referenceWithHistory,
+ new DumpLine(0, "null"), new DumpLine(1, "Foo"));
compareToString(referenceWithHistory, reference, "Foo");
// Try setting null again.
- setAndCompareReturnValue(referenceWithHistory, reference, "Foo");
- compareGet(referenceWithHistory, reference, "Foo");
- assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
- compareToString(referenceWithHistory, reference, "Foo");
+ setAndCompareReturnValue(referenceWithHistory, reference, null);
+ compareGet(referenceWithHistory, reference, null);
+ assertDumpContent(referenceWithHistory,
+ new DumpLine(1, "Foo"), new DumpLine(2, "null"));
+ compareToString(referenceWithHistory, reference, "null");
// Try a non-null value again.
setAndCompareReturnValue(referenceWithHistory, reference, "Bar");
compareGet(referenceWithHistory, reference, "Bar");
- assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+ assertDumpContent(referenceWithHistory,
+ new DumpLine(2, "null"), new DumpLine(3, "Bar"));
compareToString(referenceWithHistory, reference, "Bar");
}
@@ -132,11 +137,54 @@
assertEquals(expected, referenceWithHistory.toString());
}
- private static String dumpReferenceWithHistory(ReferenceWithHistory<?> referenceWithHistory) {
+ private static void assertDumpContent(
+ ReferenceWithHistory<?> referenceWithHistory, DumpLine... expectedLines) {
+ String[] actualLines = dumpReferenceWithHistory(referenceWithHistory);
+
+ if (expectedLines.length == 0) {
+ String expectedEmptyOutput = "{Empty}";
+ assertEquals(expectedEmptyOutput, 1, actualLines.length);
+ assertEquals(expectedEmptyOutput, actualLines[0]);
+ } else {
+ assertEquals("Expected=" + Arrays.toString(expectedLines)
+ + ", actual=" + Arrays.toString(actualLines),
+ expectedLines.length, actualLines.length);
+ for (int i = 0; i < expectedLines.length; i++) {
+ DumpLine expectedLine = expectedLines[i];
+ String actualLine = actualLines[i];
+ assertTrue("i=" + i + ", expected=" + expectedLine + ", actual=" + actualLine,
+ actualLine.startsWith(Integer.toString(expectedLine.mIndex)));
+ assertTrue("i=" + i + ", expected=" + expectedLine + ", actual=" + actualLine,
+ actualLine.endsWith(expectedLine.mLine));
+ }
+ }
+ }
+
+ private static String[] dumpReferenceWithHistory(ReferenceWithHistory<?> referenceWithHistory) {
StringWriter stringWriter = new StringWriter();
try (IndentingPrintWriter ipw = new IndentingPrintWriter(stringWriter, " ")) {
referenceWithHistory.dump(ipw);
- return stringWriter.toString();
+ return stringWriter.toString().split("\n");
+ }
+ }
+
+ /** An expected line of {@link ReferenceWithHistory#dump} output. */
+ private static class DumpLine {
+
+ final int mIndex;
+ final String mLine;
+
+ DumpLine(int index, String line) {
+ mIndex = index;
+ mLine = line;
+ }
+
+ @Override
+ public String toString() {
+ return "DumpLine{"
+ + "mIndex=" + mIndex
+ + ", mLine='" + mLine + '\''
+ + '}';
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index b4fbf5f..184ea52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -110,18 +110,20 @@
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
- t.setVisibility(leash, true /* visible */).apply();
+ t.show(leash).apply();
}
int cookieIndex = -1;
if (trampoline.equals(taskInfo.baseActivity)) {
cookieIndex = 0;
} else if (main.equals(taskInfo.baseActivity)) {
cookieIndex = 1;
- mainLatch.countDown();
}
if (cookieIndex >= 0) {
appearedCookies[cookieIndex] = taskInfo.launchCookies.isEmpty()
? null : taskInfo.launchCookies.get(0);
+ if (cookieIndex == 1) {
+ mainLatch.countDown();
+ }
}
}
};
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index cac716e..0ddd52d 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -69,7 +69,14 @@
* them know that the app has crashed and that their call was continued using the pre-loaded dialer
* app.
* <p>
- * Further, the pre-loaded dialer will ALWAYS be used when the user places an emergency call.
+ * The pre-loaded dialer will ALWAYS be used when the user places an emergency call, even if your
+ * app fills the {@link android.app.role.RoleManager#ROLE_DIALER} role. To ensure an optimal
+ * experience when placing an emergency call, the default dialer should ALWAYS use
+ * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls (including
+ * emergency calls). This ensures that the platform is able to verify that the request came from
+ * the default dialer. If a non-preloaded dialer app uses {@link Intent#ACTION_CALL} to place an
+ * emergency call, it will be raised to the preloaded dialer app using {@link Intent#ACTION_DIAL}
+ * for confirmation; this is a suboptimal user experience.
* <p>
* Below is an example manifest registration for an {@code InCallService}. The meta-data
* {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} indicates that this particular
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 4df8a4b..4016ba7 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -1,6 +1,5 @@
set noparent
-amitmahajan@google.com
breadley@google.com
fionaxu@google.com
jackyu@google.com
@@ -8,10 +7,10 @@
tgunn@google.com
jminjie@google.com
shuoq@google.com
-nazaninb@google.com
sarahchin@google.com
xiaotonj@google.com
huiwang@google.com
jayachandranc@google.com
chinmayd@google.com
amruthr@google.com
+sasindran@google.com
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index ae597e0..2b355ae 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -16,11 +16,14 @@
package android.telephony;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.RadioAccessSpecifier;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -32,7 +35,6 @@
* Network Service when passed through {@link TelephonyManager#updateAvailableNetworks}
*/
public final class AvailableNetworkInfo implements Parcelable {
-
/*
* Defines number of priority level high.
*/
@@ -48,6 +50,14 @@
*/
public static final int PRIORITY_LOW = 3;
+ /** @hide */
+ @IntDef({
+ PRIORITY_HIGH,
+ PRIORITY_MED,
+ PRIORITY_LOW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AvailableNetworkInfoPriority {}
/**
* subscription Id of the available network. This value must be one of the entry retrieved from
* {@link SubscriptionManager#getOpportunisticSubscriptions}
@@ -62,7 +72,7 @@
* for network selection. If there are more than one subId with highest priority then the
* network with highest RSRP is chosen.
*/
- private int mPriority;
+ private @AvailableNetworkInfoPriority int mPriority;
/**
* Describes the List of PLMN ids (MCC-MNC) associated with mSubId.
@@ -77,8 +87,7 @@
* Opportunistic network service will use these bands to scan.
*
* When no specific bands are specified (empty array or null) CBRS band
- * {@link AccessNetworkConstants.EutranBand.BAND_48
- * } will be used for network scan.
+ * {@link AccessNetworkConstants.EutranBand.BAND_48} will be used for network scan.
*
* See {@link AccessNetworkConstants} for details.
*
@@ -94,7 +103,7 @@
* If this entry is left empty, {@link RadioAcccessSpecifier}s with {@link AccessNetworkType}s
* of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link
* AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed
- * by Opportunistic network service.
+ * by Opportunistic network service for a network scan.
*/
private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers;
@@ -117,6 +126,7 @@
* network with highest RSRP is chosen.
* @return priority level
*/
+ @AvailableNetworkInfoPriority
public int getPriority() {
return mPriority;
}
@@ -149,15 +159,9 @@
* Returns a list of {@link RadioAccessSpecifier} associated with the available network.
* Opportunistic network service will use this to determine which bands to scan for.
*
- * the returned value is one of {@link AccessNetworkConstants.AccessNetworkType}. When no
- * specific access network type is specified, {@link RadioAccessSpecifier}s with {@link
- * AccessNetworkType}s of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link
- * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed
- * by Opportunistic network service.
* @return the access network type associated with the available network.
- * @hide
*/
- public List<RadioAccessSpecifier> getRadioAccessSpecifiers() {
+ public @NonNull List<RadioAccessSpecifier> getRadioAccessSpecifiers() {
return (List<RadioAccessSpecifier>) mRadioAccessSpecifiers.clone();
}
@@ -193,9 +197,9 @@
}
/** @hide */
- private AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs,
- @NonNull List<Integer> bands, @NonNull List<RadioAccessSpecifier>
- radioAccessSpecifiers) {
+ private AvailableNetworkInfo(int subId, @AvailableNetworkInfoPriority int priority,
+ @NonNull List<String> mccMncs, @NonNull List<Integer> bands,
+ @NonNull List<RadioAccessSpecifier> radioAccessSpecifiers) {
mSubId = subId;
mPriority = priority;
mMccMncs = new ArrayList<String>(mccMncs);
@@ -261,27 +265,39 @@
*
* <pre><code>
*
- * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder()
- * .setSubId(1)
+ * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder(subId)
* .setPriority(AvailableNetworkInfo.PRIORITY_MED)
+ * .setRadioAccessSpecifiers(radioAccessSpecifiers)
+ * .setMccMncs(mccMncs)
* .build();
* </code></pre>
- *
- * @hide
*/
public static final class Builder {
private int mSubId = Integer.MIN_VALUE;
- private int mPriority = AvailableNetworkInfo.PRIORITY_LOW;
+ private @AvailableNetworkInfoPriority int mPriority = AvailableNetworkInfo.PRIORITY_LOW;
private ArrayList<String> mMccMncs = new ArrayList<>();
- private ArrayList<Integer> mBands = new ArrayList<>();
private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers = new ArrayList<>();
- public @NonNull Builder setSubId(int subId) {
+ /**
+ *
+ */
+ /**
+ * Creates an AvailableNetworkInfo Builder with specified subscription id.
+ *
+ * @param subId of the availableNetwork.
+ */
+ public Builder(int subId) {
mSubId = subId;
- return this;
}
- public @NonNull Builder setPriority(int priority) {
+ /**
+ * Sets the priority for the subscription id.
+ *
+ * @param priority of the subscription id. See {@link AvailableNetworkInfo#getPriority} for
+ * more details
+ * @return the original Builder object.
+ */
+ public @NonNull Builder setPriority(@AvailableNetworkInfoPriority int priority) {
if (priority > AvailableNetworkInfo.PRIORITY_LOW
|| priority < AvailableNetworkInfo.PRIORITY_HIGH) {
throw new IllegalArgumentException("A valid priority must be set");
@@ -290,30 +306,48 @@
return this;
}
- public @NonNull Builder setMccMncs(@NonNull ArrayList<String> mccMncs) {
- Objects.requireNonNull(mccMncs, "A non-null ArrayList of mccmncs must be set. An empty "
- + "list is still accepted. Please read documentation in "
- + "AvailableNetworkService to see consequences of an empty Arraylist.");
- mMccMncs = mccMncs;
+ /**
+ * Sets the list of mccmncs associated with the subscription id.
+ *
+ * @param mccMncs nonull list of mccmncs. An empty List is still accepted. Please read
+ * documentation in {@link AvailableNetworkInfo} to see consequences of an empty List.
+ * @return the original Builder object.
+ */
+ public @NonNull Builder setMccMncs(@NonNull List<String> mccMncs) {
+ Objects.requireNonNull(mccMncs, "A non-null List of mccmncs must be set. An empty "
+ + "List is still accepted. Please read documentation in "
+ + "AvailableNetworkInfo to see consequences of an empty List.");
+ mMccMncs = new ArrayList<>(mccMncs);
return this;
}
+ /**
+ * Sets the list of mccmncs associated with the subscription id.
+ *
+ * @param radioAccessSpecifiers nonull list of radioAccessSpecifiers. An empty List is still
+ * accepted. Please read documentation in {@link AvailableNetworkInfo} to see
+ * consequences of an empty List.
+ * @return the original Builder object.
+ */
public @NonNull Builder setRadioAccessSpecifiers(
- @NonNull ArrayList<RadioAccessSpecifier> radioAccessSpecifiers) {
- Objects.requireNonNull(radioAccessSpecifiers, "A non-null ArrayList of "
- + "RadioAccessSpecifiers must be set. An empty list is still accepted. Please "
- + "read documentation in AvailableNetworkService to see consequences of an "
- + "empty Arraylist.");
- mRadioAccessSpecifiers = radioAccessSpecifiers;
+ @NonNull List<RadioAccessSpecifier> radioAccessSpecifiers) {
+ Objects.requireNonNull(radioAccessSpecifiers, "A non-null List of "
+ + "RadioAccessSpecifiers must be set. An empty List is still accepted. Please "
+ + "read documentation in AvailableNetworkInfo to see consequences of an "
+ + "empty List.");
+ mRadioAccessSpecifiers = new ArrayList<>(radioAccessSpecifiers);
return this;
}
+ /**
+ * @return an AvailableNetworkInfo object with all the fields previously set by the Builder.
+ */
public @NonNull AvailableNetworkInfo build() {
if (mSubId == Integer.MIN_VALUE) {
throw new IllegalArgumentException("A valid subId must be set");
}
- return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, mBands,
+ return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, new ArrayList<>(),
mRadioAccessSpecifiers);
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d11c667..894bb8e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -3674,6 +3675,49 @@
"show_wifi_calling_icon_in_status_bar_bool";
/**
+ * Configuration to indicate that the carrier supports opportunistic data
+ * auto provisioning. Based on this flag, the device downloads and activates
+ * corresponding opportunistic profile.
+ */
+ public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL =
+ "carrier_supports_opp_data_auto_provisioning_bool";
+
+ /**
+ * SMDP+ server address for downloading opportunistic eSIM profile.
+ * FQDN (Fully Qualified Domain Name) of the SM-DP+ (e.g., smdp.gsma.com) restricted to the
+ * Alphanumeric mode character set defined in table 5 of ISO/IEC 18004 [15] excluding '$'.
+ */
+ public static final String KEY_SMDP_SERVER_ADDRESS_STRING =
+ "smdp_server_address_string";
+
+ /**
+ * This timer value is used in the eSIM Exponential Backoff download retry algorithm.
+ * Value should be in seconds.
+ * <OL>
+ * <LI>When the first download failure occurs, retry download after BACKOFF_TIMER_VALUE
+ * seconds.</LI>
+ *
+ * <LI>If download fails again then, retry after either BACKOFF_TIMER_VALUE,
+ * 2xBACKOFF_TIMER_VALUE, or 3xBACKOFF_TIMER_VALUE seconds.</LI>
+ *
+ * <LI>In general after the cth failed attempt, retry after k * BACKOFF_TIMER_VALUE
+ * seconds, where k is a random integer between 1 and 2^c − 1. Max c value is
+ * {@link #KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT}</LI>
+ * </OL>
+ */
+ public static final String KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT =
+ "esim_download_retry_backoff_timer_sec_int";
+
+ /**
+ * If eSIM profile download fails then, the number of retry attempts by UE
+ * will be based on this configuration. If download still fails even after the
+ * MAX attempts configured by this item then the retry is postponed until next
+ * device bootup.
+ */
+ public static final String KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT =
+ "esim_max_download_retry_attempts_int";
+
+ /**
* Controls RSRP threshold at which OpportunisticNetworkService will decide whether
* the opportunistic network is good enough for internet data.
*/
@@ -3883,6 +3927,30 @@
public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL =
"enabled_4g_opportunistic_network_scan_bool";
+ /**
+ * Only relevant when the device supports opportunistic networks but does not support
+ * simultaneuous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network
+ * goes out of service before switching the 5G capability back to primary stack. The idea of
+ * waiting a few seconds is to minimize the calling of the expensive capability switching
+ * operation in the case where CBRS goes back into service shortly after going out of it.
+ *
+ * @hide
+ */
+ public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG =
+ "time_to_switch_back_to_primary_if_opportunistic_oos_long";
+
+ /**
+ * Only relevant when the device supports opportunistic networks but does not support
+ * simultaneuous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back
+ * to primary stack due to opportunistic network being OOS. The idea is to minimizing the
+ * 'ping-ponging' effect where device is constantly witching capability back and forth between
+ * primary and opportunistic stack.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG
+ = "opportunistic_time_to_scan_after_capability_switch_to_primary_long";
+
/**
* Indicates zero or more emergency number prefix(es), because some carrier requires
* if users dial an emergency number address with a specific prefix, the combination of the
@@ -5191,6 +5259,26 @@
"display_no_data_notification_on_permanent_failure_bool";
/**
+ * Boolean indicating if the VoNR setting is visible in the Call Settings menu.
+ * If true, the VoNR setting menu will be visible. If false, the menu will be gone.
+ *
+ * Disabled by default.
+ *
+ * @hide
+ */
+ public static final String KEY_VONR_SETTING_VISIBILITY_BOOL = "vonr_setting_visibility_bool";
+
+ /**
+ * Flag specifying whether VoNR should be enabled for carrier.
+ * If true, VoNr will be enabled. If false, hard disabled.
+ *
+ * Disabled by default.
+ *
+ * @hide
+ */
+ public static final String KEY_VONR_ENABLED_BOOL = "vonr_enabled_bool";
+
+ /**
* Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes
*
* @hide
@@ -5692,6 +5780,10 @@
sDefaults.putBoolean(KEY_UNMETERED_NR_SA_SUB6_BOOL, false);
sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_WIFI_CALLING_ICON_IN_STATUS_BAR_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, false);
+ sDefaults.putString(KEY_SMDP_SERVER_ADDRESS_STRING, "");
+ sDefaults.putInt(KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 5);
+ sDefaults.putInt(KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 60);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
@@ -5735,6 +5827,10 @@
/* Default value is 2 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000);
sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true);
+ sDefaults.putInt(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000);
+ sDefaults.putInt(
+ KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG,
+ 120000);
sDefaults.putAll(Gps.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
new int[] {
@@ -5806,6 +5902,8 @@
sDefaults.putString(KEY_CARRIER_PROVISIONING_APP_STRING, "");
sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false);
sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false);
+ sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, false);
+ sDefaults.putBoolean(KEY_VONR_ENABLED_BOOL, false);
}
/**
@@ -5874,12 +5972,15 @@
* any carrier specific configuration has been applied.
*
* <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app
+ * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
*
* @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
* @return A {@link PersistableBundle} containing the config for the given subId, or default
* values for an invalid subId.
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Nullable
public PersistableBundle getConfigForSubId(int subId) {
try {
@@ -5968,10 +6069,13 @@
* called to confirm whether any carrier specific configuration has been applied.
*
* <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app
+ * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
*
* @see #getConfigForSubId
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Nullable
public PersistableBundle getConfig() {
return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
@@ -5980,8 +6084,8 @@
/**
* Determines whether a configuration {@link PersistableBundle} obtained from
* {@link #getConfig()} or {@link #getConfigForSubId(int)} corresponds to an identified carrier.
- * <p>
- * When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED}
+ *
+ * <p>When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED}
* broadcast which informs it that the carrier configuration has changed, it is possible
* that another reload of the carrier configuration has begun since the intent was sent.
* In this case, the carrier configuration the app fetches (e.g. via {@link #getConfig()})
@@ -5990,14 +6094,12 @@
* return true because it may belong to another previous identified carrier. Users should
* always call {@link #getConfig()} or {@link #getConfigForSubId(int)} after receiving the
* broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED}.
- * </p>
- * <p>
- * After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
+ *
+ * <p>After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
* use this method to confirm whether any carrier specific configuration has been applied.
* Especially when an app misses the broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED} but it
* still needs to get the current configuration, it must use this method to verify whether the
* configuration is default or carrier overridden.
- * </p>
*
* @param bundle the configuration bundle to be checked.
* @return boolean true if any carrier specific configuration bundle has been applied, false
@@ -6009,19 +6111,20 @@
/**
* Calling this method triggers telephony services to fetch the current carrier configuration.
- * <p>
- * Normally this does not need to be called because the platform reloads config on its own.
+ *
+ * <p>Normally this does not need to be called because the platform reloads config on its own.
* This should be called by a carrier service app if it wants to update config at an arbitrary
* moment.
- * </p>
- * <p>Requires that the calling app has carrier privileges.
- * <p>
- * This method returns before the reload has completed, and
- * {@link android.service.carrier.CarrierService#onLoadConfig} will be called from an
- * arbitrary thread.
- * </p>
- * @see TelephonyManager#hasCarrierPrivileges
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or the calling app
+ * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
+ *
+ * <p>This method returns before the reload has completed, and {@link
+ * android.service.carrier.CarrierService#onLoadConfig} will be called from an arbitrary thread.
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void notifyConfigChangedForSubId(int subId) {
try {
ICarrierConfigLoader loader = getICarrierConfigLoader();
@@ -6037,11 +6140,10 @@
}
/**
- * Request the carrier config loader to update the cofig for phoneId.
- * <p>
- * Depending on simState, the config may be cleared or loaded from config app. This is only used
- * by SubscriptionInfoUpdater.
- * </p>
+ * Request the carrier config loader to update the config for phoneId.
+ *
+ * <p>Depending on simState, the config may be cleared or loaded from config app. This is only
+ * used by SubscriptionInfoUpdater.
*
* @hide
*/
@@ -6112,13 +6214,16 @@
* Gets the configuration values for a component using its prefix.
*
* <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app
+ * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
*
* @param prefix prefix of the component.
* @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
*
* @see #getConfigForSubId
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Nullable
public PersistableBundle getConfigByComponentForSubId(@NonNull String prefix, int subId) {
PersistableBundle configs = getConfigForSubId(subId);
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 42d7707..fc76f99 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -119,7 +119,7 @@
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new ImsRcsManager(mContext, subscriptionId, sRcsCache);
+ return new ImsRcsManager(mContext, subscriptionId, sRcsCache, sTelephonyCache);
}
/**
@@ -135,7 +135,7 @@
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new ImsMmTelManager(subscriptionId, sTelephonyCache);
+ return new ImsMmTelManager(mContext, subscriptionId, sTelephonyCache);
}
/**
@@ -157,7 +157,7 @@
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new SipDelegateManager(mContext, subscriptionId, sRcsCache);
+ return new SipDelegateManager(mContext, subscriptionId, sRcsCache, sTelephonyCache);
}
private static IImsRcsController getIImsRcsControllerInterface() {
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index d250088..95448c7 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -242,6 +242,11 @@
}
/**
+ * The physical cell ID which differentiates cells using the same radio channel.
+ *
+ * In GERAN, this value is the BSIC. The range is [0-63].
+ * Reference: 3GPP TS 3.03 section 4.2.2.
+ *
* In UTRAN, this value is primary scrambling code. The range is [0, 511].
* Reference: 3GPP TS 25.213 section 5.2.2.
*
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 3b44a34..d5315ac 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -949,6 +949,15 @@
public static final String VOIMS_OPT_IN_STATUS = SimInfo.COLUMN_VOIMS_OPT_IN_STATUS;
/**
+ * TelephonyProvider column name for NR Advanced calling
+ * Determines if the user has enabled VoNR settings for this subscription.
+ *
+ * @hide
+ */
+ public static final String NR_ADVANCED_CALLING_ENABLED =
+ SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED;
+
+ /**
* Profile class of the subscription
* @hide
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 122f96d..a1d68b2 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -315,6 +315,12 @@
*/
public static final int UNINITIALIZED_CARD_ID = -2;
+ /**
+ * Default port index for the UICC Card
+ * @hide
+ */
+ public static final int DEFAULT_PORT_INDEX = 0;
+
private final Context mContext;
private final int mSubId;
@UnsupportedAppUsage
@@ -12148,6 +12154,100 @@
}
/**
+ * No error. Operation succeeded.
+ * @hide
+ */
+ public static final int ENABLE_VONR_SUCCESS = 0;
+
+ /**
+ * Radio is not available.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_NOT_AVAILABLE = 2;
+
+ /**
+ * Internal Radio error.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_ERROR = 3;
+
+ /**
+ * Voice over NR enable/disable request is received when system is in invalid state.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_INVALID_STATE = 4;
+
+ /**
+ * Voice over NR enable/disable request is not supported.
+ * @hide
+ */
+ public static final int ENABLE_VONR_REQUEST_NOT_SUPPORTED = 5;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"EnableVoNrResult"}, value = {
+ ENABLE_VONR_SUCCESS,
+ ENABLE_VONR_RADIO_NOT_AVAILABLE,
+ ENABLE_VONR_RADIO_ERROR,
+ ENABLE_VONR_RADIO_INVALID_STATE,
+ ENABLE_VONR_REQUEST_NOT_SUPPORTED})
+ public @interface EnableVoNrResult {}
+
+ /**
+ * Enable or disable Voice over NR (VoNR)
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ *
+ * @param enabled enable or disable VoNR.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public @EnableVoNrResult int setVoNrEnabled(boolean enabled) {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.setVoNrEnabled(
+ getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setVoNrEnabled", e);
+ }
+
+ return ENABLE_VONR_RADIO_INVALID_STATE;
+ }
+
+ /**
+ * Is Voice over NR (VoNR) enabled.
+ * @return true if Voice over NR (VoNR) is enabled else false. Enabled state does not mean
+ * voice call over NR is active or voice ove NR is available. It means the device is allowed to
+ * register IMS over NR.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isVoNrEnabled() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isVoNrEnabled(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "isVoNrEnabled RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
* Carrier action to start or stop reporting default network available events.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
@@ -13527,15 +13627,18 @@
}
/**
- * It indicates whether modem is enabled or not per slot.
- * It's the corresponding status of TelephonyManager.enableModemForSlot.
+ * Indicates whether or not there is a modem stack enabled for the given SIM slot.
*
* <p>Requires Permission:
- * READ_PRIVILEGED_PHONE_STATE or
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE},
+ * READ_PRIVILEGED_PHONE_STATE or that the calling app has carrier privileges (see
+ * {@link #hasCarrierPrivileges()}).
+ *
* @param slotIndex which slot it's checking.
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(anyOf = {android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
public boolean isModemEnabledForSlot(int slotIndex) {
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index be1502a..1ef04be 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -147,7 +147,12 @@
}
// Possible values for authentication types.
- /** No authentication type. */
+ /**
+ * Authentication type is unknown.
+ * @hide
+ */
+ public static final int AUTH_TYPE_UNKNOWN = -1;
+ /** Authentication is not required. */
public static final int AUTH_TYPE_NONE = 0;
/** Authentication type for PAP. */
public static final int AUTH_TYPE_PAP = 1;
@@ -357,6 +362,7 @@
/** @hide */
@IntDef(prefix = { "AUTH_TYPE_" }, value = {
+ AUTH_TYPE_UNKNOWN,
AUTH_TYPE_NONE,
AUTH_TYPE_PAP,
AUTH_TYPE_CHAP,
@@ -498,7 +504,8 @@
private final String mOperatorNumeric;
private final int mProtocol;
private final int mRoamingProtocol;
- private final int mMtu;
+ private final int mMtuV4;
+ private final int mMtuV6;
private final boolean mCarrierEnabled;
@@ -522,13 +529,25 @@
private final int mSkip464Xlat;
/**
- * Returns the MTU size of the mobile interface to which the APN connected.
+ * Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
+ * is used only if MTU size is not provided in {@link DataCallResponse}.
*
* @return the MTU size of the APN
* @hide
*/
- public int getMtu() {
- return mMtu;
+ public int getMtuV4() {
+ return mMtuV4;
+ }
+
+ /**
+ * Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
+ * is used only if MTU size is not provided in {@link DataCallResponse}.
+ *
+ * @return the MTU size of the APN
+ * @hide
+ */
+ public int getMtuV6() {
+ return mMtuV6;
}
/**
@@ -879,13 +898,18 @@
this.mMmsProxyPort = builder.mMmsProxyPort;
this.mUser = builder.mUser;
this.mPassword = builder.mPassword;
- this.mAuthType = builder.mAuthType;
+ this.mAuthType = (builder.mAuthType != AUTH_TYPE_UNKNOWN)
+ ? builder.mAuthType
+ : TextUtils.isEmpty(builder.mUser)
+ ? AUTH_TYPE_NONE
+ : AUTH_TYPE_PAP_OR_CHAP;
this.mApnTypeBitmask = builder.mApnTypeBitmask;
this.mId = builder.mId;
this.mOperatorNumeric = builder.mOperatorNumeric;
this.mProtocol = builder.mProtocol;
this.mRoamingProtocol = builder.mRoamingProtocol;
- this.mMtu = builder.mMtu;
+ this.mMtuV4 = builder.mMtuV4;
+ this.mMtuV6 = builder.mMtuV6;
this.mCarrierEnabled = builder.mCarrierEnabled;
this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask;
this.mProfileId = builder.mProfileId;
@@ -903,66 +927,6 @@
/**
* @hide
*/
- public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
- String apnName, String proxyAddress, int proxyPort, Uri mmsc,
- String mmsProxyAddress, int mmsProxyPort, String user, String password,
- int authType, int mApnTypeBitmask, int protocol, int roamingProtocol,
- boolean carrierEnabled, int networkTypeBitmask, int profileId,
- boolean modemCognitive, int maxConns, int waitTime, int maxConnsTime, int mtu,
- int mvnoType, String mvnoMatchData, int apnSetId, int carrierId, int skip464xlat) {
- return new Builder()
- .setId(id)
- .setOperatorNumeric(operatorNumeric)
- .setEntryName(entryName)
- .setApnName(apnName)
- .setProxyAddress(proxyAddress)
- .setProxyPort(proxyPort)
- .setMmsc(mmsc)
- .setMmsProxyAddress(mmsProxyAddress)
- .setMmsProxyPort(mmsProxyPort)
- .setUser(user)
- .setPassword(password)
- .setAuthType(authType)
- .setApnTypeBitmask(mApnTypeBitmask)
- .setProtocol(protocol)
- .setRoamingProtocol(roamingProtocol)
- .setCarrierEnabled(carrierEnabled)
- .setNetworkTypeBitmask(networkTypeBitmask)
- .setProfileId(profileId)
- .setModemCognitive(modemCognitive)
- .setMaxConns(maxConns)
- .setWaitTime(waitTime)
- .setMaxConnsTime(maxConnsTime)
- .setMtu(mtu)
- .setMvnoType(mvnoType)
- .setMvnoMatchData(mvnoMatchData)
- .setApnSetId(apnSetId)
- .setCarrierId(carrierId)
- .setSkip464Xlat(skip464xlat)
- .buildWithoutCheck();
- }
-
- /**
- * @hide
- */
- public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
- String apnName, String proxyAddress, int proxyPort, Uri mmsc,
- String mmsProxyAddress, int mmsProxyPort, String user, String password,
- int authType, int mApnTypeBitmask, int protocol, int roamingProtocol,
- boolean carrierEnabled, int networkTypeBitmask, int profileId, boolean modemCognitive,
- int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType,
- String mvnoMatchData) {
- return makeApnSetting(id, operatorNumeric, entryName, apnName, proxyAddress, proxyPort,
- mmsc, mmsProxyAddress, mmsProxyPort, user, password, authType, mApnTypeBitmask,
- protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, profileId,
- modemCognitive, maxConns, waitTime, maxConnsTime, mtu, mvnoType, mvnoMatchData,
- Carriers.NO_APN_SET_ID, TelephonyManager.UNKNOWN_CARRIER_ID,
- Carriers.SKIP_464XLAT_DEFAULT);
- }
-
- /**
- * @hide
- */
public static ApnSetting makeApnSetting(Cursor cursor) {
final int apnTypesBitmask = getApnTypesBitmaskFromString(
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
@@ -975,272 +939,99 @@
ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
}
- return makeApnSetting(
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
- cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
- portFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
- UriFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
- cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
- portFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
- apnTypesBitmask,
- getProtocolIntFromString(
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))),
- getProtocolIntFromString(
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.ROAMING_PROTOCOL))),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.CARRIER_ENABLED)) == 1,
- networkTypeBitmask,
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MODEM_PERSIST)) == 1,
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
- getMvnoTypeIntFromString(
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MVNO_TYPE))),
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MVNO_MATCH_DATA)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT)));
+ return new Builder()
+ .setId(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)))
+ .setOperatorNumeric(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)))
+ .setEntryName(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)))
+ .setApnName(cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)))
+ .setProxyAddress(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)))
+ .setProxyPort(portFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))))
+ .setMmsc(UriFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))))
+ .setMmsProxyAddress(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)))
+ .setMmsProxyPort(portFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))))
+ .setUser(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)))
+ .setPassword(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)))
+ .setAuthType(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)))
+ .setApnTypeBitmask(apnTypesBitmask)
+ .setProtocol(getProtocolIntFromString(
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))))
+ .setRoamingProtocol(getProtocolIntFromString(
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.ROAMING_PROTOCOL))))
+ .setCarrierEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.CARRIER_ENABLED)) == 1)
+ .setNetworkTypeBitmask(networkTypeBitmask)
+ .setProfileId(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)))
+ .setModemCognitive(cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MODEM_PERSIST)) == 1)
+ .setMaxConns(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS)))
+ .setWaitTime(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)))
+ .setMaxConnsTime(cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)))
+ .setMtuV4(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)))
+ .setMtuV6(UNSET_MTU) // TODO: Add corresponding support in telephony provider
+ .setMvnoType(getMvnoTypeIntFromString(
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MVNO_TYPE))))
+ .setMvnoMatchData(cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MVNO_MATCH_DATA)))
+ .setApnSetId(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)))
+ .setCarrierId(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)))
+ .setSkip464Xlat(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT)))
+ .buildWithoutCheck();
}
/**
* @hide
*/
public static ApnSetting makeApnSetting(ApnSetting apn) {
- return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName,
- apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
- apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
- apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
- apn.mProfileId, apn.mPersistent, apn.mMaxConns, apn.mWaitTime,
- apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId,
- apn.mCarrierId, apn.mSkip464Xlat);
- }
-
- /**
- * Creates an ApnSetting object from a string.
- *
- * @param data the string to read.
- *
- * The string must be in one of two formats (newlines added for clarity,
- * spaces are optional):
- *
- * v1 format:
- * <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...],
- *
- * v2 format:
- * [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- *
- * v3 format:
- * [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>
- *
- * v4 format:
- * [ApnSettingV4] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>
- *
- * v5 format:
- * [ApnSettingV5] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>
- *
- * v6 format:
- * [ApnSettingV6] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId>
- *
- * v7 format:
- * [ApnSettingV7] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId>, <skip464xlat>
- *
- * Note that the strings generated by {@link #toString()} do not contain the username
- * and password and thus cannot be read by this method.
- *
- * This method may return {@code null} if the input string is invalid.
- *
- * @hide
- */
- public static ApnSetting fromString(String data) {
- if (data == null) return null;
-
- int version;
- // matches() operates on the whole string, so append .* to the regex.
- if (data.matches(V7_FORMAT_REGEX + ".*")) {
- version = 7;
- data = data.replaceFirst(V7_FORMAT_REGEX, "");
- } else if (data.matches(V6_FORMAT_REGEX + ".*")) {
- version = 6;
- data = data.replaceFirst(V6_FORMAT_REGEX, "");
- } else if (data.matches(V5_FORMAT_REGEX + ".*")) {
- version = 5;
- data = data.replaceFirst(V5_FORMAT_REGEX, "");
- } else if (data.matches(V4_FORMAT_REGEX + ".*")) {
- version = 4;
- data = data.replaceFirst(V4_FORMAT_REGEX, "");
- } else if (data.matches(V3_FORMAT_REGEX + ".*")) {
- version = 3;
- data = data.replaceFirst(V3_FORMAT_REGEX, "");
- } else if (data.matches(V2_FORMAT_REGEX + ".*")) {
- version = 2;
- data = data.replaceFirst(V2_FORMAT_REGEX, "");
- } else {
- version = 1;
- }
-
- String[] a = data.split("\\s*,\\s*", -1);
- if (a.length < 14) {
- return null;
- }
-
- int authType;
- try {
- authType = Integer.parseInt(a[12]);
- } catch (NumberFormatException e) {
- authType = 0;
- }
-
- String[] typeArray;
- String protocol, roamingProtocol;
- boolean carrierEnabled;
- int bearerBitmask = 0;
- int networkTypeBitmask = 0;
- int profileId = 0;
- boolean modemCognitive = false;
- int maxConns = 0;
- int waitTime = 0;
- int maxConnsTime = 0;
- int mtu = UNSET_MTU;
- String mvnoType = "";
- String mvnoMatchData = "";
- int apnSetId = Carriers.NO_APN_SET_ID;
- int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
- int skip464xlat = Carriers.SKIP_464XLAT_DEFAULT;
- if (version == 1) {
- typeArray = new String[a.length - 13];
- System.arraycopy(a, 13, typeArray, 0, a.length - 13);
- protocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP);
- roamingProtocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP);
- carrierEnabled = true;
- } else {
- if (a.length < 18) {
- return null;
- }
- typeArray = a[13].split("\\s*\\|\\s*");
- protocol = a[14];
- roamingProtocol = a[15];
- carrierEnabled = Boolean.parseBoolean(a[16]);
-
- bearerBitmask = ServiceState.getBitmaskFromString(a[17]);
-
- if (a.length > 22) {
- modemCognitive = Boolean.parseBoolean(a[19]);
- try {
- profileId = Integer.parseInt(a[18]);
- maxConns = Integer.parseInt(a[20]);
- waitTime = Integer.parseInt(a[21]);
- maxConnsTime = Integer.parseInt(a[22]);
- } catch (NumberFormatException e) {
- }
- }
- if (a.length > 23) {
- try {
- mtu = Integer.parseInt(a[23]);
- } catch (NumberFormatException e) {
- }
- }
- if (a.length > 25) {
- mvnoType = a[24];
- mvnoMatchData = a[25];
- }
- if (a.length > 26) {
- networkTypeBitmask = ServiceState.getBitmaskFromString(a[26]);
- }
- if (a.length > 27) {
- apnSetId = Integer.parseInt(a[27]);
- }
- if (a.length > 28) {
- carrierId = Integer.parseInt(a[28]);
- }
- if (a.length > 29) {
- try {
- skip464xlat = Integer.parseInt(a[29]);
- } catch (NumberFormatException e) {
- }
- }
- }
-
- // If both bearerBitmask and networkTypeBitmask were specified, bearerBitmask would be
- // ignored.
- if (networkTypeBitmask == 0) {
- networkTypeBitmask =
- ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
- }
- return makeApnSetting(-1, a[10] + a[11], a[0], a[1], a[2],
- portFromString(a[3]), UriFromString(a[7]), a[8],
- portFromString(a[9]), a[4], a[5], authType,
- getApnTypesBitmaskFromString(TextUtils.join(",", typeArray)),
- getProtocolIntFromString(protocol), getProtocolIntFromString(roamingProtocol),
- carrierEnabled, networkTypeBitmask, profileId, modemCognitive, maxConns, waitTime,
- maxConnsTime, mtu, getMvnoTypeIntFromString(mvnoType), mvnoMatchData, apnSetId,
- carrierId, skip464xlat);
- }
-
- /**
- * Creates an array of ApnSetting objects from a string.
- *
- * @param data the string to read.
- *
- * Builds on top of the same format used by fromString, but allows for multiple entries
- * separated by ";".
- *
- * @hide
- */
- public static List<ApnSetting> arrayFromString(String data) {
- List<ApnSetting> retVal = new ArrayList<ApnSetting>();
- if (TextUtils.isEmpty(data)) {
- return retVal;
- }
- String[] apnStrings = data.split("\\s*;\\s*");
- for (String apnString : apnStrings) {
- ApnSetting apn = fromString(apnString);
- if (apn != null) {
- retVal.add(apn);
- }
- }
- return retVal;
+ return new Builder()
+ .setId(apn.mId)
+ .setOperatorNumeric(apn.mOperatorNumeric)
+ .setEntryName(apn.mEntryName)
+ .setApnName(apn.mApnName)
+ .setProxyAddress(apn.mProxyAddress)
+ .setProxyPort(apn.mProxyPort)
+ .setMmsc(apn.mMmsc)
+ .setMmsProxyAddress(apn.mMmsProxyAddress)
+ .setMmsProxyPort(apn.mMmsProxyPort)
+ .setUser(apn.mUser)
+ .setPassword(apn.mPassword)
+ .setAuthType(apn.mAuthType)
+ .setApnTypeBitmask(apn.mApnTypeBitmask)
+ .setProtocol(apn.mProtocol)
+ .setRoamingProtocol(apn.mRoamingProtocol)
+ .setCarrierEnabled(apn.mCarrierEnabled)
+ .setNetworkTypeBitmask(apn.mNetworkTypeBitmask)
+ .setProfileId(apn.mProfileId)
+ .setModemCognitive(apn.mPersistent)
+ .setMaxConns(apn.mMaxConns)
+ .setWaitTime(apn.mWaitTime)
+ .setMaxConnsTime(apn.mMaxConnsTime)
+ .setMtuV4(apn.mMtuV4)
+ .setMtuV6(apn.mMtuV6)
+ .setMvnoType(apn.mMvnoType)
+ .setMvnoMatchData(apn.mMvnoMatchData)
+ .setApnSetId(apn.mApnSetId)
+ .setCarrierId(apn.mCarrierId)
+ .setSkip464Xlat(apn.mSkip464Xlat)
+ .buildWithoutCheck();
}
/**
@@ -1251,7 +1042,7 @@
*/
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("[ApnSettingV7] ")
+ sb.append("[ApnSetting] ")
.append(mEntryName)
.append(", ").append(mId)
.append(", ").append(mOperatorNumeric)
@@ -1272,7 +1063,8 @@
sb.append(", ").append(mMaxConns);
sb.append(", ").append(mWaitTime);
sb.append(", ").append(mMaxConnsTime);
- sb.append(", ").append(mMtu);
+ sb.append(", ").append(mMtuV4);
+ sb.append(", ").append(mMtuV6);
sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType));
sb.append(", ").append(mMvnoMatchData);
sb.append(", ").append(mPermanentFailed);
@@ -1343,9 +1135,9 @@
public int hashCode() {
return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress,
mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric,
- mProtocol, mRoamingProtocol, mMtu, mCarrierEnabled, mNetworkTypeBitmask, mProfileId,
- mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, mMvnoMatchData,
- mApnSetId, mCarrierId, mSkip464Xlat);
+ mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask,
+ mProfileId, mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType,
+ mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat);
}
@Override
@@ -1357,33 +1149,34 @@
ApnSetting other = (ApnSetting) o;
return mEntryName.equals(other.mEntryName)
- && Objects.equals(mId, other.mId)
- && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
- && Objects.equals(mApnName, other.mApnName)
- && Objects.equals(mProxyAddress, other.mProxyAddress)
- && Objects.equals(mMmsc, other.mMmsc)
- && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
- && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort, other.mProxyPort)
- && Objects.equals(mUser, other.mUser)
- && Objects.equals(mPassword, other.mPassword)
- && Objects.equals(mAuthType, other.mAuthType)
- && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && Objects.equals(mProtocol, other.mProtocol)
- && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
- && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
- && Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mPersistent, other.mPersistent)
- && Objects.equals(mMaxConns, other.mMaxConns)
- && Objects.equals(mWaitTime, other.mWaitTime)
- && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
- && Objects.equals(mMtu, other.mMtu)
- && Objects.equals(mMvnoType, other.mMvnoType)
- && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
- && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
- && Objects.equals(mApnSetId, other.mApnSetId)
- && Objects.equals(mCarrierId, other.mCarrierId)
- && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
+ && Objects.equals(mId, other.mId)
+ && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+ && Objects.equals(mApnName, other.mApnName)
+ && Objects.equals(mProxyAddress, other.mProxyAddress)
+ && Objects.equals(mMmsc, other.mMmsc)
+ && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+ && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
+ && Objects.equals(mUser, other.mUser)
+ && Objects.equals(mPassword, other.mPassword)
+ && Objects.equals(mAuthType, other.mAuthType)
+ && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+ && Objects.equals(mProtocol, other.mProtocol)
+ && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
+ && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+ && Objects.equals(mProfileId, other.mProfileId)
+ && Objects.equals(mPersistent, other.mPersistent)
+ && Objects.equals(mMaxConns, other.mMaxConns)
+ && Objects.equals(mWaitTime, other.mWaitTime)
+ && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+ && Objects.equals(mMtuV4, other.mMtuV4)
+ && Objects.equals(mMtuV6, other.mMtuV6)
+ && Objects.equals(mMvnoType, other.mMvnoType)
+ && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+ && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+ && Objects.equals(mApnSetId, other.mApnSetId)
+ && Objects.equals(mCarrierId, other.mCarrierId)
+ && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
}
/**
@@ -1406,31 +1199,32 @@
ApnSetting other = (ApnSetting) o;
return mEntryName.equals(other.mEntryName)
- && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
- && Objects.equals(mApnName, other.mApnName)
- && Objects.equals(mProxyAddress, other.mProxyAddress)
- && Objects.equals(mMmsc, other.mMmsc)
- && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
- && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort, other.mProxyPort)
- && Objects.equals(mUser, other.mUser)
- && Objects.equals(mPassword, other.mPassword)
- && Objects.equals(mAuthType, other.mAuthType)
- && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
- && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
- && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
- && Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mPersistent, other.mPersistent)
- && Objects.equals(mMaxConns, other.mMaxConns)
- && Objects.equals(mWaitTime, other.mWaitTime)
- && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
- && Objects.equals(mMtu, other.mMtu)
- && Objects.equals(mMvnoType, other.mMvnoType)
- && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
- && Objects.equals(mApnSetId, other.mApnSetId)
- && Objects.equals(mCarrierId, other.mCarrierId)
- && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
+ && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+ && Objects.equals(mApnName, other.mApnName)
+ && Objects.equals(mProxyAddress, other.mProxyAddress)
+ && Objects.equals(mMmsc, other.mMmsc)
+ && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+ && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
+ && Objects.equals(mUser, other.mUser)
+ && Objects.equals(mPassword, other.mPassword)
+ && Objects.equals(mAuthType, other.mAuthType)
+ && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+ && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
+ && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
+ && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+ && Objects.equals(mProfileId, other.mProfileId)
+ && Objects.equals(mPersistent, other.mPersistent)
+ && Objects.equals(mMaxConns, other.mMaxConns)
+ && Objects.equals(mWaitTime, other.mWaitTime)
+ && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+ && Objects.equals(mMtuV4, other.mMtuV4)
+ && Objects.equals(mMtuV6, other.mMtuV6)
+ && Objects.equals(mMvnoType, other.mMvnoType)
+ && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+ && Objects.equals(mApnSetId, other.mApnSetId)
+ && Objects.equals(mCarrierId, other.mCarrierId)
+ && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
}
/**
@@ -1732,7 +1526,7 @@
dest.writeString(mApnName);
dest.writeString(mProxyAddress);
dest.writeInt(mProxyPort);
- dest.writeValue(mMmsc);
+ dest.writeParcelable(mMmsc, flags);
dest.writeString(mMmsProxyAddress);
dest.writeInt(mMmsProxyPort);
dest.writeString(mUser);
@@ -1742,40 +1536,53 @@
dest.writeInt(mProtocol);
dest.writeInt(mRoamingProtocol);
dest.writeBoolean(mCarrierEnabled);
- dest.writeInt(mMvnoType);
dest.writeInt(mNetworkTypeBitmask);
+ dest.writeInt(mProfileId);
+ dest.writeBoolean(mPersistent);
+ dest.writeInt(mMaxConns);
+ dest.writeInt(mWaitTime);
+ dest.writeInt(mMaxConnsTime);
+ dest.writeInt(mMtuV4);
+ dest.writeInt(mMtuV6);
+ dest.writeInt(mMvnoType);
+ dest.writeString(mMvnoMatchData);
dest.writeInt(mApnSetId);
dest.writeInt(mCarrierId);
dest.writeInt(mSkip464Xlat);
}
private static ApnSetting readFromParcel(Parcel in) {
- final int id = in.readInt();
- final String operatorNumeric = in.readString();
- final String entryName = in.readString();
- final String apnName = in.readString();
- final String proxy = in.readString();
- final int port = in.readInt();
- final Uri mmsc = (Uri) in.readValue(Uri.class.getClassLoader());
- final String mmsProxy = in.readString();
- final int mmsPort = in.readInt();
- final String user = in.readString();
- final String password = in.readString();
- final int authType = in.readInt();
- final int apnTypesBitmask = in.readInt();
- final int protocol = in.readInt();
- final int roamingProtocol = in.readInt();
- final boolean carrierEnabled = in.readBoolean();
- final int mvnoType = in.readInt();
- final int networkTypeBitmask = in.readInt();
- final int apnSetId = in.readInt();
- final int carrierId = in.readInt();
- final int skip464xlat = in.readInt();
-
- return makeApnSetting(id, operatorNumeric, entryName, apnName,
- proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, apnTypesBitmask,
- protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false,
- 0, 0, 0, 0, mvnoType, null, apnSetId, carrierId, skip464xlat);
+ return new Builder()
+ .setId(in.readInt())
+ .setOperatorNumeric(in.readString())
+ .setEntryName(in.readString())
+ .setApnName(in.readString())
+ .setProxyAddress(in.readString())
+ .setProxyPort(in.readInt())
+ .setMmsc(in.readParcelable(Uri.class.getClassLoader()))
+ .setMmsProxyAddress(in.readString())
+ .setMmsProxyPort(in.readInt())
+ .setUser(in.readString())
+ .setPassword(in.readString())
+ .setAuthType(in.readInt())
+ .setApnTypeBitmask(in.readInt())
+ .setProtocol(in.readInt())
+ .setRoamingProtocol(in.readInt())
+ .setCarrierEnabled(in.readBoolean())
+ .setNetworkTypeBitmask(in.readInt())
+ .setProfileId(in.readInt())
+ .setModemCognitive(in.readBoolean())
+ .setMaxConns(in.readInt())
+ .setWaitTime(in.readInt())
+ .setMaxConnsTime(in.readInt())
+ .setMtuV4(in.readInt())
+ .setMtuV6(in.readInt())
+ .setMvnoType(in.readInt())
+ .setMvnoMatchData(in.readString())
+ .setApnSetId(in.readInt())
+ .setCarrierId(in.readInt())
+ .setSkip464Xlat(in.readInt())
+ .buildWithoutCheck();
}
public static final @android.annotation.NonNull Parcelable.Creator<ApnSetting> CREATOR =
@@ -1834,13 +1641,14 @@
private int mMmsProxyPort = UNSPECIFIED_INT;
private String mUser;
private String mPassword;
- private int mAuthType;
+ private int mAuthType = AUTH_TYPE_UNKNOWN;
private int mApnTypeBitmask;
private int mId;
private String mOperatorNumeric;
private int mProtocol = UNSPECIFIED_INT;
private int mRoamingProtocol = UNSPECIFIED_INT;
- private int mMtu;
+ private int mMtuV4;
+ private int mMtuV6;
private int mNetworkTypeBitmask;
private boolean mCarrierEnabled;
private int mProfileId;
@@ -1863,20 +1671,34 @@
* Sets the unique database id for this entry.
*
* @param id the unique database id to set for this entry
+ * @hide
*/
- private Builder setId(int id) {
+ public Builder setId(int id) {
this.mId = id;
return this;
}
/**
- * Set the MTU size of the mobile interface to which the APN connected.
+ * Set the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
+ * is used only if MTU size is not provided in {@link DataCallResponse}.
*
- * @param mtu the MTU size to set for the APN
+ * @param mtuV4 the MTU size to set for the APN
* @hide
*/
- public Builder setMtu(int mtu) {
- this.mMtu = mtu;
+ public Builder setMtuV4(int mtuV4) {
+ this.mMtuV4 = mtuV4;
+ return this;
+ }
+
+ /**
+ * Set the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
+ * is used only if MTU size is not provided in {@link DataCallResponse}.
+ *
+ * @param mtuV6 the MTU size to set for the APN
+ * @hide
+ */
+ public Builder setMtuV6(int mtuV6) {
+ this.mMtuV6 = mtuV6;
return this;
}
@@ -2237,7 +2059,8 @@
| TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX
| TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0
|| TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) {
- return null;
+ throw new IllegalArgumentException("mApName=" + mApnName + ", mEntryName="
+ + mEntryName + ", mApnTypeBitmask=" + mApnTypeBitmask);
}
return new ApnSetting(this);
}
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index f2a1249..93903d2 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -25,13 +25,11 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.Annotation.ApnType;
+import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.NetworkTypeBitMask;
import android.telephony.data.ApnSetting.AuthType;
import android.text.TextUtils;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.util.TelephonyUtils;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -62,152 +60,141 @@
/** 3GPP2 type data profile */
public static final int TYPE_3GPP2 = 2;
- private final int mProfileId;
+ private final @Type int mType;
- private final String mApn;
+ private final @Nullable ApnSetting mApnSetting;
- @ProtocolType
- private final int mProtocolType;
-
- @AuthType
- private final int mAuthType;
-
- private final String mUserName;
-
- private final String mPassword;
-
- @Type
- private final int mType;
-
- private final int mMaxConnectionsTime;
-
- private final int mMaxConnections;
-
- private final int mWaitTime;
-
- private final boolean mEnabled;
-
- @ApnType
- private final int mSupportedApnTypesBitmask;
-
- @ProtocolType
- private final int mRoamingProtocolType;
-
- @NetworkTypeBitMask
- private final int mBearerBitmask;
-
- private final int mMtuV4;
-
- private final int mMtuV6;
-
- private final boolean mPersistent;
+ private final @Nullable TrafficDescriptor mTrafficDescriptor;
private final boolean mPreferred;
- /** @hide */
- private DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType,
- String userName, String password, int type, int maxConnectionsTime,
- int maxConnections, int waitTime, boolean enabled,
- @ApnType int supportedApnTypesBitmask, @ProtocolType int roamingProtocolType,
- @NetworkTypeBitMask int bearerBitmask, int mtuV4, int mtuV6, boolean persistent,
- boolean preferred) {
- this.mProfileId = profileId;
- this.mApn = apn;
- this.mProtocolType = protocolType;
- if (authType == -1) {
- authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE
- : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
+ private DataProfile(@NonNull Builder builder) {
+ mApnSetting = builder.mApnSetting;
+ mTrafficDescriptor = builder.mTrafficDescriptor;
+ mPreferred = builder.mPreferred;
+
+ if (builder.mType != -1) {
+ mType = builder.mType;
+ } else if (mApnSetting != null) {
+ int networkTypes = mApnSetting.getNetworkTypeBitmask();
+
+ if (networkTypes == 0) {
+ mType = DataProfile.TYPE_COMMON;
+ } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2)
+ == networkTypes) {
+ mType = DataProfile.TYPE_3GPP2;
+ } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP)
+ == networkTypes) {
+ mType = DataProfile.TYPE_3GPP;
+ } else {
+ mType = DataProfile.TYPE_COMMON;
+ }
+ } else {
+ mType = DataProfile.TYPE_COMMON;
}
- this.mAuthType = authType;
- this.mUserName = userName;
- this.mPassword = password;
- this.mType = type;
- this.mMaxConnectionsTime = maxConnectionsTime;
- this.mMaxConnections = maxConnections;
- this.mWaitTime = waitTime;
- this.mEnabled = enabled;
- this.mSupportedApnTypesBitmask = supportedApnTypesBitmask;
- this.mRoamingProtocolType = roamingProtocolType;
- this.mBearerBitmask = bearerBitmask;
- this.mMtuV4 = mtuV4;
- this.mMtuV6 = mtuV6;
- this.mPersistent = persistent;
- this.mPreferred = preferred;
}
private DataProfile(Parcel source) {
- mProfileId = source.readInt();
- mApn = source.readString();
- mProtocolType = source.readInt();
- mAuthType = source.readInt();
- mUserName = source.readString();
- mPassword = source.readString();
mType = source.readInt();
- mMaxConnectionsTime = source.readInt();
- mMaxConnections = source.readInt();
- mWaitTime = source.readInt();
- mEnabled = source.readBoolean();
- mSupportedApnTypesBitmask = source.readInt();
- mRoamingProtocolType = source.readInt();
- mBearerBitmask = source.readInt();
- mMtuV4 = source.readInt();
- mMtuV6 = source.readInt();
- mPersistent = source.readBoolean();
+ mApnSetting = source.readParcelable(ApnSetting.class.getClassLoader());
+ mTrafficDescriptor = source.readParcelable(TrafficDescriptor.class.getClassLoader());
mPreferred = source.readBoolean();
}
/**
* @return Id of the data profile.
*/
- public int getProfileId() { return mProfileId; }
+ public int getProfileId() {
+ if (mApnSetting != null) {
+ return mApnSetting.getProfileId();
+ }
+ return 0;
+ }
/**
* @return The APN (Access Point Name) to establish data connection. This is a string
* specifically defined by the carrier.
*/
@NonNull
- public String getApn() { return mApn; }
+ public String getApn() {
+ if (mApnSetting != null) {
+ return TextUtils.emptyIfNull(mApnSetting.getApnName());
+ }
+ return "";
+ }
/**
* @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
*/
- public @ProtocolType int getProtocolType() { return mProtocolType; }
+ public @ProtocolType int getProtocolType() {
+ if (mApnSetting != null) {
+ return mApnSetting.getProtocol();
+ }
+ return ApnSetting.PROTOCOL_IP;
+ }
/**
* @return The authentication protocol used for this PDP context.
*/
- public @AuthType int getAuthType() { return mAuthType; }
+ public @AuthType int getAuthType() {
+ if (mApnSetting != null) {
+ return mApnSetting.getAuthType();
+ }
+ return ApnSetting.AUTH_TYPE_NONE;
+ }
/**
* @return The username for APN. Can be null.
*/
@Nullable
- public String getUserName() { return mUserName; }
+ public String getUserName() {
+ if (mApnSetting != null) {
+ return mApnSetting.getUser();
+ }
+ return null;
+ }
/**
* @return The password for APN. Can be null.
*/
@Nullable
- public String getPassword() { return mPassword; }
+ public String getPassword() {
+ if (mApnSetting != null) {
+ return mApnSetting.getPassword();
+ }
+ return null;
+ }
/**
* @return The profile type.
*/
- public @Type int getType() { return mType; }
+ public @Type int getType() {
+ return mType;
+ }
/**
* @return The period in seconds to limit the maximum connections.
*
* @hide
*/
- public int getMaxConnectionsTime() { return mMaxConnectionsTime; }
+ public int getMaxConnectionsTime() {
+ if (mApnSetting != null) {
+ return mApnSetting.getMaxConnsTime();
+ }
+ return 0;
+ }
/**
* @return The maximum connections allowed.
*
* @hide
*/
- public int getMaxConnections() { return mMaxConnections; }
+ public int getMaxConnections() {
+ if (mApnSetting != null) {
+ return mApnSetting.getMaxConns();
+ }
+ return 0;
+ }
/**
* @return The required wait time in seconds after a successful UE initiated disconnect of a
@@ -216,57 +203,117 @@
*
* @hide
*/
- public int getWaitTime() { return mWaitTime; }
+ public int getWaitTime() {
+ if (mApnSetting != null) {
+ return mApnSetting.getWaitTime();
+ }
+ return 0;
+ }
/**
* @return True if the profile is enabled.
*/
- public boolean isEnabled() { return mEnabled; }
+ public boolean isEnabled() {
+ if (mApnSetting != null) {
+ return mApnSetting.isEnabled();
+ }
+ return false;
+ }
/**
* @return The supported APN types bitmask.
*/
- public @ApnType int getSupportedApnTypesBitmask() { return mSupportedApnTypesBitmask; }
+ public @ApnType int getSupportedApnTypesBitmask() {
+ if (mApnSetting != null) {
+ return mApnSetting.getApnTypeBitmask();
+ }
+ return ApnSetting.TYPE_NONE;
+ }
/**
* @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1.
*/
- public @ProtocolType int getRoamingProtocolType() { return mRoamingProtocolType; }
+ public @ProtocolType int getRoamingProtocolType() {
+ if (mApnSetting != null) {
+ return mApnSetting.getRoamingProtocol();
+ }
+ return ApnSetting.PROTOCOL_IP;
+ }
/**
* @return The bearer bitmask indicating the applicable networks for this data profile.
*/
- public @NetworkTypeBitMask int getBearerBitmask() { return mBearerBitmask; }
+ public @NetworkTypeBitMask int getBearerBitmask() {
+ if (mApnSetting != null) {
+ return mApnSetting.getNetworkTypeBitmask();
+ }
+ return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN;
+ }
/**
* @return The maximum transmission unit (MTU) size in bytes.
* @deprecated use {@link #getMtuV4} or {@link #getMtuV6} instead.
*/
@Deprecated
- public int getMtu() { return mMtuV4; }
+ public int getMtu() {
+ return getMtuV4();
+ }
/**
* This replaces the deprecated method getMtu.
* @return The maximum transmission unit (MTU) size in bytes, for IPv4.
*/
- public int getMtuV4() { return mMtuV4; }
+ public int getMtuV4() {
+ if (mApnSetting != null) {
+ return mApnSetting.getMtuV4();
+ }
+ return 0;
+ }
/**
* @return The maximum transmission unit (MTU) size in bytes, for IPv6.
*/
- public int getMtuV6() { return mMtuV6; }
+ public int getMtuV6() {
+ if (mApnSetting != null) {
+ return mApnSetting.getMtuV6();
+ }
+ return 0;
+ }
/**
* @return {@code true} if modem must persist this data profile.
*/
- public boolean isPersistent() { return mPersistent; }
+ public boolean isPersistent() {
+ if (mApnSetting != null) {
+ return mApnSetting.isPersistent();
+ }
+ return false;
+ }
/**
* @return {@code true} if this data profile was used to bring up the last default
* (i.e internet) data connection successfully, or the one chosen by the user in Settings'
* APN editor. For one carrier there can be only one profiled preferred.
*/
- public boolean isPreferred() { return mPreferred; }
+ public boolean isPreferred() {
+ return mPreferred;
+ }
+
+ /**
+ * @return The APN setting
+ * @hide TODO: Remove before T is released.
+ */
+ public @Nullable ApnSetting getApnSetting() {
+ return mApnSetting;
+ }
+
+ /**
+ * @return The traffic descriptor
+ * @hide TODO: Remove before T is released.
+ */
+ public @Nullable TrafficDescriptor getTrafficDescriptor() {
+ return mTrafficDescriptor;
+ }
@Override
public int describeContents() {
@@ -276,34 +323,15 @@
@NonNull
@Override
public String toString() {
- return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType
- + "/" + (TelephonyUtils.IS_USER ? "***/***/***" :
- (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
- + mMaxConnectionsTime + "/" + mMaxConnections + "/"
- + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmask + "/"
- + mRoamingProtocolType + "/" + mBearerBitmask + "/" + mMtuV4 + "/" + mMtuV6 + "/"
- + mPersistent + "/" + mPreferred;
+ return "DataProfile=" + mApnSetting + ", " + mTrafficDescriptor + ", preferred="
+ + mPreferred;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mProfileId);
- dest.writeString(mApn);
- dest.writeInt(mProtocolType);
- dest.writeInt(mAuthType);
- dest.writeString(mUserName);
- dest.writeString(mPassword);
dest.writeInt(mType);
- dest.writeInt(mMaxConnectionsTime);
- dest.writeInt(mMaxConnections);
- dest.writeInt(mWaitTime);
- dest.writeBoolean(mEnabled);
- dest.writeInt(mSupportedApnTypesBitmask);
- dest.writeInt(mRoamingProtocolType);
- dest.writeInt(mBearerBitmask);
- dest.writeInt(mMtuV4);
- dest.writeInt(mMtuV6);
- dest.writeBoolean(mPersistent);
+ dest.writeParcelable(mApnSetting, flags);
+ dest.writeParcelable(mTrafficDescriptor, flags);
dest.writeBoolean(mPreferred);
}
@@ -321,36 +349,18 @@
};
@Override
- public boolean equals(@Nullable Object o) {
+ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DataProfile that = (DataProfile) o;
- return mProfileId == that.mProfileId
- && mProtocolType == that.mProtocolType
- && mAuthType == that.mAuthType
- && mType == that.mType
- && mMaxConnectionsTime == that.mMaxConnectionsTime
- && mMaxConnections == that.mMaxConnections
- && mWaitTime == that.mWaitTime
- && mEnabled == that.mEnabled
- && mSupportedApnTypesBitmask == that.mSupportedApnTypesBitmask
- && mRoamingProtocolType == that.mRoamingProtocolType
- && mBearerBitmask == that.mBearerBitmask
- && mMtuV4 == that.mMtuV4
- && mMtuV6 == that.mMtuV6
- && mPersistent == that.mPersistent
- && mPreferred == that.mPreferred
- && Objects.equals(mApn, that.mApn)
- && Objects.equals(mUserName, that.mUserName)
- && Objects.equals(mPassword, that.mPassword);
+ return mType == that.mType
+ && Objects.equals(mApnSetting, that.mApnSetting)
+ && Objects.equals(mTrafficDescriptor, that.mTrafficDescriptor);
}
@Override
public int hashCode() {
- return Objects.hash(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, mType,
- mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled,
- mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6,
- mPersistent, mPreferred);
+ return Objects.hash(mType, mApnSetting, mTrafficDescriptor);
}
/**
@@ -383,13 +393,7 @@
private String mPassword;
@Type
- private int mType;
-
- private int mMaxConnectionsTime;
-
- private int mMaxConnections;
-
- private int mWaitTime;
+ private int mType = -1;
private boolean mEnabled;
@@ -410,6 +414,10 @@
private boolean mPreferred;
+ private ApnSetting mApnSetting;
+
+ private TrafficDescriptor mTrafficDescriptor;
+
/**
* Default constructor for Builder.
*/
@@ -496,48 +504,6 @@
}
/**
- * Set the period in seconds to limit the maximum connections.
- *
- * @param maxConnectionsTime The profile type
- * @return The same instance of the builder.
- *
- * @hide
- */
- public @NonNull Builder setMaxConnectionsTime(int maxConnectionsTime) {
- mMaxConnectionsTime = maxConnectionsTime;
- return this;
- }
-
- /**
- * Set the maximum connections allowed.
- *
- * @param maxConnections The maximum connections allowed.
- * @return The same instance of the builder.
- *
- * @hide
- */
- public @NonNull Builder setMaxConnections(int maxConnections) {
- mMaxConnections = maxConnections;
- return this;
- }
-
- /**
- * Set the period in seconds to limit the maximum connections.
- *
- * @param waitTime The required wait time in seconds after a successful UE initiated
- * disconnect of a given PDN connection before the device can send a new PDN connection
- * request for that given PDN.
- *
- * @return The same instance of the builder.
- *
- * @hide
- */
- public @NonNull Builder setWaitTime(int waitTime) {
- mWaitTime = waitTime;
- return this;
- }
-
- /**
* Enable the data profile
*
* @param isEnabled {@code true} to enable the data profile, otherwise disable.
@@ -587,8 +553,9 @@
*
* @param mtu The maximum transmission unit (MTU) size in bytes.
* @return The same instance of the builder.
- * @deprecated use {@link #setMtuV4} or {@link #setMtuV6} instead.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} instead.
*/
+ @Deprecated
public @NonNull Builder setMtu(int mtu) {
mMtuV4 = mMtuV6 = mtu;
return this;
@@ -631,7 +598,7 @@
}
/**
- * Set data profile as persistent/non-persistent
+ * Set data profile as persistent/non-persistent.
*
* @param isPersistent {@code true} if this data profile was used to bring up the last
* default (i.e internet) data connection successfully.
@@ -643,15 +610,63 @@
}
/**
+ * Set APN setting.
+ *
+ * @param apnSetting APN setting
+ * @return The same instance of the builder
+ *
+ * @hide // TODO: Remove before T is released.
+ */
+ public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) {
+ mApnSetting = apnSetting;
+ return this;
+ }
+
+ /**
+ * Set traffic descriptor.
+ *
+ * @param trafficDescriptor Traffic descriptor
+ * @return The same instance of the builder
+ *
+ * @hide // TODO: Remove before T is released.
+ */
+ public @NonNull Builder setTrafficDescriptor(@NonNull TrafficDescriptor trafficDescriptor) {
+ mTrafficDescriptor = trafficDescriptor;
+ return this;
+ }
+
+ /**
* Build the DataProfile object
*
* @return The data profile object
*/
public @NonNull DataProfile build() {
- return new DataProfile(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword,
- mType, mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled,
- mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6,
- mPersistent, mPreferred);
+ if (mApnSetting == null && mApn != null) {
+ // This is for backwards compatibility.
+ mApnSetting = new ApnSetting.Builder()
+ .setEntryName(mApn)
+ .setApnName(mApn)
+ .setApnTypeBitmask(mSupportedApnTypesBitmask)
+ .setAuthType(mAuthType)
+ .setCarrierEnabled(mEnabled)
+ .setModemCognitive(mPersistent)
+ .setMtuV4(mMtuV4)
+ .setMtuV6(mMtuV6)
+ .setNetworkTypeBitmask(mBearerBitmask)
+ .setProfileId(mProfileId)
+ .setPassword(mPassword)
+ .setProtocol(mProtocolType)
+ .setRoamingProtocol(mRoamingProtocolType)
+ .setUser(mUserName)
+ .build();
+ }
+
+ if (mApnSetting == null && mTrafficDescriptor == null) {
+ throw new IllegalArgumentException("APN setting and traffic descriptor can't be "
+ + "both null.");
+ }
+
+ return new DataProfile(this);
}
}
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 36082dc..683bb92 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -25,6 +25,7 @@
import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -45,6 +46,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -214,6 +216,7 @@
}
}
+ private final Context mContext;
private final int mSubId;
private final BinderCacheManager<ITelephony> mBinderCache;
@@ -255,6 +258,16 @@
*/
@VisibleForTesting
public ImsMmTelManager(int subId, BinderCacheManager<ITelephony> binderCache) {
+ this(null, subId, binderCache);
+ }
+
+ /**
+ * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
+ * @hide
+ */
+ @VisibleForTesting
+ public ImsMmTelManager(Context context, int subId, BinderCacheManager<ITelephony> binderCache) {
+ mContext = context;
mSubId = subId;
mBinderCache = binderCache;
}
@@ -1482,6 +1495,74 @@
}
}
+ /**
+ * Register a new callback, which is used to notify the registrant of changes to
+ * the state of the underlying IMS service that is attached to telephony to
+ * implement IMS functionality. If the manager is created for
+ * the {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
+ * this throws an {@link ImsException}.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
+ * or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor the Executor that will be used to call the {@link ImsStateCallback}.
+ * @param callback The callback instance being registered.
+ * @throws ImsException in the case that the callback can not be registered.
+ * See {@link ImsException#getCode} for more information on when this is called.
+ */
+ @RequiresPermission(anyOf = {Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
+ public void registerImsStateCallback(@NonNull Executor executor,
+ @NonNull ImsStateCallback callback) throws ImsException {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+ Objects.requireNonNull(executor, "Must include a non-null Executor.");
+
+ callback.init(executor);
+ ITelephony telephony = mBinderCache.listenOnBinder(callback, callback::binderDied);
+ if (telephony == null) {
+ throw new ImsException("Telephony server is down",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
+ try {
+ telephony.registerImsStateCallback(
+ mSubId, ImsFeature.FEATURE_MMTEL,
+ callback.getCallbackBinder(), getOpPackageName());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
+ } catch (RemoteException | IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Unregisters a previously registered callback.
+ *
+ * @param callback The callback instance to be unregistered.
+ */
+ public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+
+ ITelephony telephony = mBinderCache.removeRunnable(callback);
+ try {
+ if (telephony != null) {
+ telephony.unregisterImsStateCallback(callback.getCallbackBinder());
+ }
+ } catch (RemoteException ignore) {
+ // ignore it
+ }
+ }
+
+ private String getOpPackageName() {
+ if (mContext != null) {
+ return mContext.getOpPackageName();
+ } else {
+ return null;
+ }
+ }
+
private ITelephony getITelephony() {
return mBinderCache.getBinder();
}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 8d6fa41..1b047c7 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -39,9 +39,11 @@
import android.util.Log;
import com.android.internal.telephony.IIntegerConsumer;
+import com.android.internal.telephony.ITelephony;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -159,6 +161,7 @@
private final int mSubId;
private final Context mContext;
private final BinderCacheManager<IImsRcsController> mBinderCache;
+ private final BinderCacheManager<ITelephony> mTelephonyBinderCache;
private final Map<OnAvailabilityChangedListener, AvailabilityCallbackAdapter>
mAvailabilityChangedCallbacks;
@@ -167,11 +170,13 @@
* @hide
*/
public ImsRcsManager(Context context, int subId,
- BinderCacheManager<IImsRcsController> binderCache) {
+ BinderCacheManager<IImsRcsController> binderCache,
+ BinderCacheManager<ITelephony> telephonyBinderCache) {
mSubId = subId;
mContext = context;
mBinderCache = binderCache;
mAvailabilityChangedCallbacks = new HashMap<>();
+ mTelephonyBinderCache = telephonyBinderCache;
}
/**
@@ -534,6 +539,67 @@
}
/**
+ * Register a new callback, which is used to notify the registrant of changes to
+ * the state of the underlying IMS service that is attached to telephony to
+ * implement IMS functionality. If the manager is created for
+ * the {@link android.telephony.SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
+ * this throws an {@link ImsException}.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
+ * or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor the Executor that will be used to call the {@link ImsStateCallback}.
+ * @param callback The callback instance being registered.
+ * @throws ImsException in the case that the callback can not be registered.
+ * See {@link ImsException#getCode} for more information on when this is called.
+ */
+ @RequiresPermission(anyOf = {Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE})
+ public void registerImsStateCallback(@NonNull Executor executor,
+ @NonNull ImsStateCallback callback) throws ImsException {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+ Objects.requireNonNull(executor, "Must include a non-null Executor.");
+
+ callback.init(executor);
+ ITelephony telephony = mTelephonyBinderCache.listenOnBinder(callback, callback::binderDied);
+ if (telephony == null) {
+ throw new ImsException("Telephony server is down",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
+ try {
+ telephony.registerImsStateCallback(
+ mSubId, ImsFeature.FEATURE_RCS,
+ callback.getCallbackBinder(), mContext.getOpPackageName());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
+ } catch (RemoteException | IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Unregisters a previously registered callback.
+ *
+ * @param callback The callback instance to be unregistered.
+ */
+ public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+
+ ITelephony telephony = mTelephonyBinderCache.removeRunnable(callback);
+ try {
+ if (telephony != null) {
+ telephony.unregisterImsStateCallback(callback.getCallbackBinder());
+ }
+ } catch (RemoteException ignore) {
+ // ignore it
+ }
+ }
+
+ /**
* Add the {@link OnAvailabilityChangedListener} to collection for tracking.
* @param executor The executor that will be used when the publish state is changed and the
* {@link OnAvailabilityChangedListener} is called.
diff --git a/telephony/java/android/telephony/ims/ImsStateCallback.java b/telephony/java/android/telephony/ims/ImsStateCallback.java
new file mode 100644
index 0000000..b9ba93f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsStateCallback.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Binder;
+
+import com.android.internal.telephony.IImsStateCallback;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Executor;
+
+/**
+ * A callback class used for monitoring changes in IMS service connection states
+ * for a specific subscription.
+ * <p>
+ * @see ImsMmTelManager#registerImsStateCallback(Executor, ImsStateCallback)
+ * @see ImsRcsManager#registerImsStateCallback(Executor, ImsStateCallback)
+ */
+public abstract class ImsStateCallback {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "REASON_", value = {
+ REASON_UNKNOWN_TEMPORARY_ERROR,
+ REASON_UNKNOWN_PERMANENT_ERROR,
+ REASON_IMS_SERVICE_DISCONNECTED,
+ REASON_NO_IMS_SERVICE_CONFIGURED,
+ REASON_SUBSCRIPTION_INACTIVE,
+ REASON_IMS_SERVICE_NOT_READY
+ })
+ public @interface DisconnectedReason {}
+
+ /**
+ * The underlying IMS service is temporarily unavailable for the
+ * associated subscription.
+ * {@link #onAvailable} will be called when the IMS service becomes
+ * available again.
+ */
+ public static final int REASON_UNKNOWN_TEMPORARY_ERROR = 1;
+
+ /**
+ * The underlying IMS service is permanently unavailable for the
+ * associated subscription and there will be no Manager available for
+ * this subscription.
+ */
+ public static final int REASON_UNKNOWN_PERMANENT_ERROR = 2;
+
+ /**
+ * The underlying IMS service has died, is reconfiguring, or has never
+ * come up yet and as a result is currently unavailable.
+ * {@link #onAvailable} will be called when the IMS service becomes
+ * available. All callbacks should be unregistered now and registered again
+ * if the IMS service moves back to available.
+ */
+ public static final int REASON_IMS_SERVICE_DISCONNECTED = 3;
+
+ /**
+ * There is no IMS service configured for the subscription ID specified.
+ * This is a permanent error and there will be no Manager available for
+ * this subscription.
+ */
+ public static final int REASON_NO_IMS_SERVICE_CONFIGURED = 4;
+
+ /**
+ * The subscription associated with this Manager has moved to an inactive
+ * state (e.g. SIM removed) and the IMS service has torn down the resources
+ * related to this subscription. This has caused this callback
+ * to be deregistered. The callback must be re-registered when this subscription
+ * becomes active in order to continue listening to the IMS service state.
+ */
+ public static final int REASON_SUBSCRIPTION_INACTIVE = 5;
+
+ /**
+ * The IMS service is connected, but in a NOT_READY state. Once the
+ * service moves to ready, {@link #onAvailable} will be called.
+ */
+ public static final int REASON_IMS_SERVICE_NOT_READY = 6;
+
+ private IImsStateCallbackStub mCallback;
+
+ /**
+ * @hide
+ */
+ public void init(@NonNull @CallbackExecutor Executor executor) {
+ if (executor == null) {
+ throw new IllegalArgumentException("ImsStateCallback Executor must be non-null");
+ }
+ mCallback = new IImsStateCallbackStub(this, executor);
+ }
+
+ /**
+ * Using a static class and weak reference here to avoid memory leak caused by the
+ * IImsStateCallback.Stub callback retaining references to the outside ImsStateCallback.
+ */
+ private static class IImsStateCallbackStub extends IImsStateCallback.Stub {
+ private WeakReference<ImsStateCallback> mImsStateCallbackWeakRef;
+ private Executor mExecutor;
+
+ IImsStateCallbackStub(ImsStateCallback imsStateCallback, Executor executor) {
+ mImsStateCallbackWeakRef = new WeakReference<ImsStateCallback>(imsStateCallback);
+ mExecutor = executor;
+ }
+
+ Executor getExecutor() {
+ return mExecutor;
+ }
+
+ public void onAvailable() {
+ ImsStateCallback callback = mImsStateCallbackWeakRef.get();
+ if (callback == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> callback.onAvailable()));
+ }
+
+ public void onUnavailable(int reason) {
+ ImsStateCallback callback = mImsStateCallbackWeakRef.get();
+ if (callback == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> callback.onUnavailable(reason)));
+ }
+ }
+
+ /**
+ * The IMS service has disconnected or is reporting NOT_READY and is no longer
+ * available to users. The user should clean up all related state and
+ * unregister callbacks. If it is a temporary error, {@link #onAvailable} will
+ * be called when the IMS service becomes available again.
+ *
+ * @param reason the specified reason
+ */
+ public abstract void onUnavailable(@DisconnectedReason int reason);
+
+ /**
+ * The IMS service is connected and is ready for communication over the
+ * provided Manager.
+ */
+ public abstract void onAvailable();
+
+ /**
+ * An unexpected error has occurred and the Telephony process has crashed. This
+ * has caused this callback to be deregistered. The callback must be
+ * re-registered in order to continue listening to the IMS service state.
+ */
+ public abstract void onError();
+
+ /**
+ * The callback to notify the death of telephony process
+ * @hide
+ */
+ public final void binderDied() {
+ if (mCallback != null) {
+ mCallback.getExecutor().execute(() -> onError());
+ }
+ }
+
+ /**
+ * Return the callback binder
+ * @hide
+ */
+ public IImsStateCallbackStub getCallbackBinder() {
+ return mCallback;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index 5a80663..f913df5 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -28,15 +28,16 @@
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.telephony.BinderCacheManager;
-import android.telephony.CarrierConfigManager;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper;
+import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
import android.telephony.ims.stub.SipDelegate;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.ITelephony;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -282,6 +283,7 @@
private final Context mContext;
private final int mSubId;
private final BinderCacheManager<IImsRcsController> mBinderCache;
+ private final BinderCacheManager<ITelephony> mTelephonyBinderCache;
/**
* Only visible for testing. To instantiate an instance of this class, please use
@@ -290,10 +292,12 @@
*/
@VisibleForTesting
public SipDelegateManager(Context context, int subId,
- BinderCacheManager<IImsRcsController> binderCache) {
+ BinderCacheManager<IImsRcsController> binderCache,
+ BinderCacheManager<ITelephony> telephonyBinderCache) {
mContext = context;
mSubId = subId;
mBinderCache = binderCache;
+ mTelephonyBinderCache = telephonyBinderCache;
}
/**
@@ -446,4 +450,65 @@
+ " into this method");
}
}
+
+ /**
+ * Register a new callback, which is used to notify the registrant of changes to
+ * the state of the underlying IMS service that is attached to telephony to
+ * implement IMS functionality. If the manager is created for
+ * the {@link android.telephony.SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
+ * this throws an {@link ImsException}.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
+ * or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor the Executor that will be used to call the {@link ImsStateCallback}.
+ * @param callback The callback instance being registered.
+ * @throws ImsException in the case that the callback can not be registered.
+ * See {@link ImsException#getCode} for more information on when this is called.
+ */
+ @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION})
+ public void registerImsStateCallback(@NonNull Executor executor,
+ @NonNull ImsStateCallback callback) throws ImsException {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+ Objects.requireNonNull(executor, "Must include a non-null Executor.");
+
+ callback.init(executor);
+ ITelephony telephony = mTelephonyBinderCache.listenOnBinder(callback, callback::binderDied);
+ if (telephony == null) {
+ throw new ImsException("Telephony server is down",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
+ try {
+ telephony.registerImsStateCallback(
+ mSubId, ImsFeature.FEATURE_RCS,
+ callback.getCallbackBinder(), mContext.getOpPackageName());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
+ } catch (RemoteException | IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Unregisters a previously registered callback.
+ *
+ * @param callback The callback instance to be unregistered.
+ */
+ public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+
+ ITelephony telephony = mTelephonyBinderCache.removeRunnable(callback);
+
+ try {
+ if (telephony != null) {
+ telephony.unregisterImsStateCallback(callback.getCallbackBinder());
+ }
+ } catch (RemoteException ignore) {
+ // ignore it
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/IImsStateCallback.aidl b/telephony/java/com/android/internal/telephony/IImsStateCallback.aidl
new file mode 100644
index 0000000..e04b01d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IImsStateCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+oneway interface IImsStateCallback {
+ void onUnavailable(int reason);
+ void onAvailable();
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 232a5d8..6b33a68 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -67,6 +67,7 @@
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IBooleanConsumer;
import com.android.internal.telephony.ICallForwardingInfoCallback;
+import com.android.internal.telephony.IImsStateCallback;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.INumberVerificationCallback;
import com.android.internal.telephony.OperatorInfo;
@@ -2224,6 +2225,20 @@
List<String> getEquivalentHomePlmns(int subId, String callingPackage, String callingFeatureId);
/**
+ * Enable or disable Voice over NR (VoNR)
+ * @param subId the subscription ID that this action applies to.
+ * @param enabled enable or disable VoNR.
+ * @return operation result.
+ */
+ int setVoNrEnabled(int subId, boolean enabled);
+
+ /**
+ * Is voice over NR enabled
+ * @return true if VoNR is enabled else false
+ */
+ boolean isVoNrEnabled(int subId);
+
+ /**
* Enable/Disable E-UTRA-NR Dual Connectivity
* @return operation result. See TelephonyManager.EnableNrDualConnectivityResult for
* details
@@ -2483,4 +2498,15 @@
* NSSAIs (configured, allowed and rejected).
*/
void getSlicingConfig(in ResultReceiver callback);
+
+ /**
+ * Register an IMS connection state callback
+ */
+ void registerImsStateCallback(int subId, int feature, in IImsStateCallback cb,
+ in String callingPackage);
+
+ /**
+ * Unregister an IMS connection state callback
+ */
+ void unregisterImsStateCallback(in IImsStateCallback cb);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index b73f827..866fd2c 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -528,6 +528,8 @@
int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP = 222;
int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP = 223;
int RIL_REQUEST_GET_SLICING_CONFIG = 224;
+ int RIL_REQUEST_ENABLE_VONR = 225;
+ int RIL_REQUEST_IS_VONR_ENABLED = 226;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/tests/FlickerTests/OWNERS b/tests/FlickerTests/OWNERS
index b556101..c1221e3 100644
--- a/tests/FlickerTests/OWNERS
+++ b/tests/FlickerTests/OWNERS
@@ -1,3 +1,4 @@
# Bug component: 909476
include /services/core/java/com/android/server/wm/OWNERS
-natanieljr@google.com
\ No newline at end of file
+natanieljr@google.com
+pablogamito@google.com
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 5253c3e..2b0037e 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -16,6 +16,7 @@
package com.android.server.vcn;
+import static android.net.IpSecManager.IpSecTunnelInterface;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
@@ -24,6 +25,8 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
+import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
@@ -36,8 +39,11 @@
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.net.IpSecManager;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -59,6 +65,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.InetAddress;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -71,6 +79,8 @@
public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
private static final int TEST_UID = Process.myUid() + 1;
+ private static final String LOOPBACK_IFACE = "lo";
+
private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
private static final int TEST_SIM_SLOT_INDEX = 1;
private static final int TEST_SUBSCRIPTION_ID_1 = 2;
@@ -78,6 +88,12 @@
private static final int TEST_SUBSCRIPTION_ID_2 = 3;
private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
+ private static final String TEST_TCP_BUFFER_SIZES = "1,2,3,4,5,6";
+ private static final int TEST_MTU = 1300;
+ private static final int TEST_MTU_DELTA = 64;
+ private static final List<LinkAddress> TEST_INTERNAL_ADDRESSES =
+ Arrays.asList(new LinkAddress(DUMMY_ADDR, 16));
+ private static final List<InetAddress> TEST_DNS_ADDRESSES = Arrays.asList(DUMMY_ADDR);
private static final int TEST_UPSTREAM_BANDWIDTH = 1234;
private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345;
@@ -169,6 +185,59 @@
}
@Test
+ public void testBuildLinkProperties() throws Exception {
+ final IpSecTunnelInterface tunnelIface =
+ mContext.getSystemService(IpSecManager.class)
+ .createIpSecTunnelInterface(
+ DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network);
+
+ final LinkProperties underlyingLp = new LinkProperties();
+ underlyingLp.setInterfaceName(LOOPBACK_IFACE);
+ underlyingLp.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES);
+ doReturn(TEST_MTU).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
+
+ final VcnChildSessionConfiguration childSessionConfig =
+ mock(VcnChildSessionConfiguration.class);
+ doReturn(TEST_INTERNAL_ADDRESSES).when(childSessionConfig).getInternalAddresses();
+ doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers();
+
+ UnderlyingNetworkRecord record =
+ new UnderlyingNetworkRecord(
+ mock(Network.class, CALLS_REAL_METHODS),
+ new NetworkCapabilities.Builder().build(),
+ underlyingLp,
+ false);
+
+ final LinkProperties vcnLp1 =
+ mGatewayConnection.buildConnectedLinkProperties(
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ tunnelIface,
+ childSessionConfig,
+ record);
+
+ verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
+
+ // Instead of having to recalculate the final MTU (after accounting for IPsec overhead),
+ // calculate another set of Link Properties with a lower MTU, and calculate the delta.
+ doReturn(TEST_MTU - TEST_MTU_DELTA).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
+
+ final LinkProperties vcnLp2 =
+ mGatewayConnection.buildConnectedLinkProperties(
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ tunnelIface,
+ childSessionConfig,
+ record);
+
+ verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
+
+ assertEquals(tunnelIface.getInterfaceName(), vcnLp1.getInterfaceName());
+ assertEquals(TEST_INTERNAL_ADDRESSES, vcnLp1.getLinkAddresses());
+ assertEquals(TEST_DNS_ADDRESSES, vcnLp1.getDnsServers());
+ assertEquals(TEST_TCP_BUFFER_SIZES, vcnLp1.getTcpBufferSizes());
+ assertEquals(TEST_MTU_DELTA, vcnLp1.getMtu() - vcnLp2.getMtu());
+ }
+
+ @Test
public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() {
verifyWakeLockSetUp();
diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS
index 69dfcc9..4f655e5 100644
--- a/tools/aapt2/OWNERS
+++ b/tools/aapt2/OWNERS
@@ -1,4 +1,4 @@
set noparent
toddke@google.com
-rtmitchell@google.com
+zyy@google.com
patb@google.com
\ No newline at end of file
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 5d57de6..be09545 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -154,7 +154,7 @@
const char* end = path.end();
const char* last_dir_sep = path.begin();
for (const char* c = path.begin(); c != end; ++c) {
- if (*c == sDirSep) {
+ if (*c == sDirSep || *c == sInvariantDirSep) {
last_dir_sep = c + 1;
}
}
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index 481a4cd..e50cb50 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -41,6 +41,8 @@
constexpr const char sPathSep = ':';
#endif
+constexpr const char sInvariantDirSep = '/';
+
enum class FileType {
kUnknown = 0,
kNonexistant,