Merge "Change isCISCentralSupported() to isLeAudioSupported() API"
diff --git a/Android.bp b/Android.bp
index 5851f43..f8a9e0f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -69,6 +69,7 @@
// Java/AIDL sources under frameworks/base
":framework-annotations",
":framework-blobstore-sources",
+ ":framework-connectivity-nsd-sources",
":framework-core-sources",
":framework-drm-sources",
":framework-graphics-nonupdatable-sources",
diff --git a/apex/media/framework/java/android/media/MediaTranscodingManager.java b/apex/media/framework/java/android/media/MediaTranscodingManager.java
index 93d58d0..1a84929 100644
--- a/apex/media/framework/java/android/media/MediaTranscodingManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodingManager.java
@@ -952,6 +952,8 @@
*
* @return the video track format to be used if transcoding should be performed,
* and null otherwise.
+ * @throws IllegalArgumentException if the hinted source video format contains invalid
+ * parameters.
*/
@Nullable
public MediaFormat resolveVideoFormat() {
@@ -962,20 +964,19 @@
MediaFormat videoTrackFormat = new MediaFormat(mSrcVideoFormatHint);
videoTrackFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC);
- int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH);
- int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT);
+ int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH, -1);
+ int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT, -1);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException(
"Source Width and height must be larger than 0");
}
- float frameRate = 30.0f; // default to 30fps.
- if (mSrcVideoFormatHint.containsKey(MediaFormat.KEY_FRAME_RATE)) {
- frameRate = mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE);
- if (frameRate <= 0) {
- throw new IllegalArgumentException(
- "frameRate must be larger than 0");
- }
+ float frameRate =
+ mSrcVideoFormatHint.getNumber(MediaFormat.KEY_FRAME_RATE, 30.0)
+ .floatValue();
+ if (frameRate <= 0) {
+ throw new IllegalArgumentException(
+ "frameRate must be larger than 0");
}
int bitrate = getAVCBitrate(width, height, frameRate);
diff --git a/boot/boot-image-profile.txt b/boot/boot-image-profile.txt
index 5f27cc7..82269d4 100644
--- a/boot/boot-image-profile.txt
+++ b/boot/boot-image-profile.txt
@@ -2899,10 +2899,8 @@
HSPLandroid/app/assist/AssistStructure$ViewNode;->getChildCount()I
HSPLandroid/app/assist/AssistStructure$ViewNode;->writeSelfToParcel(Landroid/os/Parcel;Landroid/os/PooledStringWriter;Z[FZ)I+]Landroid/view/autofill/AutofillId;Landroid/view/autofill/AutofillId;]Landroid/graphics/Matrix;Landroid/graphics/Matrix;]Landroid/app/assist/AssistStructure$ViewNodeText;Landroid/app/assist/AssistStructure$ViewNodeText;]Landroid/os/Parcel;Landroid/os/Parcel;
HSPLandroid/app/assist/AssistStructure$ViewNode;->writeString(Landroid/os/Parcel;Landroid/os/PooledStringWriter;Ljava/lang/String;)V+]Landroid/os/PooledStringWriter;Landroid/os/PooledStringWriter;]Landroid/os/Parcel;Landroid/os/Parcel;
-HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;-><init>()V
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->getChildCount()I
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->getNodeText()Landroid/app/assist/AssistStructure$ViewNodeText;
-HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->getViewNode()Landroid/app/assist/AssistStructure$ViewNode;
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->newChild(I)Landroid/view/ViewStructure;
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->setAutofillHints([Ljava/lang/String;)V
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->setAutofillId(Landroid/view/autofill/AutofillId;)V
@@ -3883,8 +3881,6 @@
HSPLandroid/content/ContentResolver$ResultListener;-><init>(Landroid/content/ContentResolver$1;)V
HSPLandroid/content/ContentResolver$ResultListener;->onResult(Landroid/os/Bundle;)V+]Landroid/os/ParcelableException;Landroid/os/ParcelableException;]Ljava/lang/Object;Landroid/content/ContentResolver$StringResultListener;,Landroid/content/ContentResolver$UriResultListener;]Landroid/os/Bundle;Landroid/os/Bundle;]Landroid/content/ContentResolver$ResultListener;Landroid/content/ContentResolver$UriResultListener;,Landroid/content/ContentResolver$StringResultListener;
HSPLandroid/content/ContentResolver$ResultListener;->waitForResult(J)V+]Ljava/lang/Object;Landroid/content/ContentResolver$StringResultListener;
-HSPLandroid/content/ContentResolver$StringResultListener;-><init>()V
-HSPLandroid/content/ContentResolver$StringResultListener;-><init>(Landroid/content/ContentResolver$1;)V
HSPLandroid/content/ContentResolver$StringResultListener;->getResultFromBundle(Landroid/os/Bundle;)Ljava/lang/Object;+]Landroid/content/ContentResolver$StringResultListener;Landroid/content/ContentResolver$StringResultListener;
HSPLandroid/content/ContentResolver$StringResultListener;->getResultFromBundle(Landroid/os/Bundle;)Ljava/lang/String;+]Landroid/os/Bundle;Landroid/os/Bundle;
HSPLandroid/content/ContentResolver;-><init>(Landroid/content/Context;)V
@@ -7029,7 +7025,6 @@
HSPLandroid/graphics/Region$1;->createFromParcel(Landroid/os/Parcel;)Landroid/graphics/Region;
HSPLandroid/graphics/Region$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;+]Landroid/graphics/Region$1;Landroid/graphics/Region$1;
HSPLandroid/graphics/Region;-><init>()V
-HSPLandroid/graphics/Region;-><init>(IIII)V
HSPLandroid/graphics/Region;-><init>(J)V
HSPLandroid/graphics/Region;->access$000(Landroid/os/Parcel;)J
HSPLandroid/graphics/Region;->equals(Ljava/lang/Object;)Z
@@ -7075,7 +7070,6 @@
HSPLandroid/graphics/RenderNode;->hasDisplayList()Z
HSPLandroid/graphics/RenderNode;->hasIdentityMatrix()Z
HSPLandroid/graphics/RenderNode;->isAttached()Z+]Landroid/graphics/RenderNode$AnimationHost;Landroid/view/ViewAnimationHostBridge;
-HSPLandroid/graphics/RenderNode;->isPivotExplicitlySet()Z
HSPLandroid/graphics/RenderNode;->offsetTopAndBottom(I)Z
HSPLandroid/graphics/RenderNode;->setAlpha(F)Z
HSPLandroid/graphics/RenderNode;->setAnimationMatrix(Landroid/graphics/Matrix;)Z+]Landroid/graphics/Matrix;Landroid/graphics/Matrix;
@@ -8283,7 +8277,6 @@
HSPLandroid/hardware/GeomagneticField$LegendreTable;-><init>(IF)V
HSPLandroid/hardware/GeomagneticField;-><init>(FFFJ)V
HSPLandroid/hardware/GeomagneticField;->computeGeocentricCoordinates(FFF)V
-HSPLandroid/hardware/GeomagneticField;->getDeclination()F
HSPLandroid/hardware/HardwareBuffer$1;->createFromParcel(Landroid/os/Parcel;)Landroid/hardware/HardwareBuffer;
HSPLandroid/hardware/HardwareBuffer$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
HSPLandroid/hardware/HardwareBuffer;-><init>(J)V+]Llibcore/util/NativeAllocationRegistry;Llibcore/util/NativeAllocationRegistry;]Ljava/lang/Class;Ljava/lang/Class;]Ldalvik/system/CloseGuard;Ldalvik/system/CloseGuard;
@@ -11353,7 +11346,6 @@
HSPLandroid/media/SoundPool$EventHandler;->handleMessage(Landroid/os/Message;)V
HSPLandroid/media/SoundPool;-><init>(ILandroid/media/AudioAttributes;)V
HSPLandroid/media/SoundPool;-><init>(ILandroid/media/AudioAttributes;Landroid/media/SoundPool$1;)V
-HSPLandroid/media/SoundPool;->load(Ljava/lang/String;I)I
HSPLandroid/media/SoundPool;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
HSPLandroid/media/SoundPool;->setOnLoadCompleteListener(Landroid/media/SoundPool$OnLoadCompleteListener;)V
HSPLandroid/media/SubtitleController$1;->handleMessage(Landroid/os/Message;)Z
@@ -11389,10 +11381,8 @@
HSPLandroid/media/Utils;->sortDistinctRanges([Landroid/util/Range;)V
HSPLandroid/media/audiofx/AudioEffect$Descriptor;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
HSPLandroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;-><init>(II[Landroid/media/AudioAttributes;)V
-HSPLandroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;->supportsStreamType(I)Z
HSPLandroid/media/audiopolicy/AudioProductStrategy;-><init>(Ljava/lang/String;I[Landroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;)V
HSPLandroid/media/audiopolicy/AudioProductStrategy;->attributesMatches(Landroid/media/AudioAttributes;Landroid/media/AudioAttributes;)Z+]Landroid/media/AudioAttributes;Landroid/media/AudioAttributes;
-HSPLandroid/media/audiopolicy/AudioProductStrategy;->getAudioAttributesForLegacyStreamType(I)Landroid/media/AudioAttributes;+]Landroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;Landroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;
HSPLandroid/media/audiopolicy/AudioProductStrategy;->getAudioAttributesForStrategyWithLegacyStreamType(I)Landroid/media/AudioAttributes;
HSPLandroid/media/audiopolicy/AudioProductStrategy;->getAudioProductStrategies()Ljava/util/List;
HSPLandroid/media/audiopolicy/AudioProductStrategy;->getLegacyStreamTypeForStrategyWithAudioAttributes(Landroid/media/AudioAttributes;)I+]Landroid/media/audiopolicy/AudioProductStrategy;Landroid/media/audiopolicy/AudioProductStrategy;]Ljava/util/List;Ljava/util/ArrayList;]Ljava/util/Iterator;Ljava/util/ArrayList$Itr;
@@ -13125,7 +13115,6 @@
HSPLandroid/os/ParcelableParcel$1;->createFromParcel(Landroid/os/Parcel;)Landroid/os/ParcelableParcel;
HSPLandroid/os/ParcelableParcel$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
HSPLandroid/os/ParcelableParcel;-><init>(Landroid/os/Parcel;Ljava/lang/ClassLoader;)V
-HSPLandroid/os/ParcelableParcel;-><init>(Ljava/lang/ClassLoader;)V
HSPLandroid/os/ParcelableParcel;->getClassLoader()Ljava/lang/ClassLoader;
HSPLandroid/os/ParcelableParcel;->getParcel()Landroid/os/Parcel;
HSPLandroid/os/ParcelableParcel;->writeToParcel(Landroid/os/Parcel;I)V
@@ -13481,7 +13470,6 @@
HSPLandroid/os/Temperature;-><init>(FILjava/lang/String;I)V
HSPLandroid/os/Temperature;->getStatus()I
HSPLandroid/os/Temperature;->isValidStatus(I)Z
-HSPLandroid/os/Temperature;->isValidType(I)Z
HSPLandroid/os/ThreadLocalWorkSource$$ExternalSyntheticLambda0;->get()Ljava/lang/Object;
HSPLandroid/os/ThreadLocalWorkSource;->getToken()J+]Ljava/lang/Integer;Ljava/lang/Integer;]Ljava/lang/ThreadLocal;Ljava/lang/ThreadLocal$SuppliedThreadLocal;
HSPLandroid/os/ThreadLocalWorkSource;->getUid()I+]Ljava/lang/Integer;Ljava/lang/Integer;]Ljava/lang/ThreadLocal;Ljava/lang/ThreadLocal$SuppliedThreadLocal;
@@ -18488,7 +18476,6 @@
HSPLandroid/view/ViewRootImpl$ImeInputStage;-><init>(Landroid/view/ViewRootImpl;Landroid/view/ViewRootImpl$InputStage;Ljava/lang/String;)V
HSPLandroid/view/ViewRootImpl$ImeInputStage;->onFinishedInputEvent(Ljava/lang/Object;Z)V
HSPLandroid/view/ViewRootImpl$ImeInputStage;->onProcess(Landroid/view/ViewRootImpl$QueuedInputEvent;)I
-HSPLandroid/view/ViewRootImpl$InputMetricsListener;-><init>(Landroid/view/ViewRootImpl;)V
HSPLandroid/view/ViewRootImpl$InputMetricsListener;->onFrameMetricsAvailable(I)V+]Landroid/view/ViewRootImpl$WindowInputEventReceiver;Landroid/view/ViewRootImpl$WindowInputEventReceiver;]Ljava/lang/StringBuilder;Ljava/lang/StringBuilder;]Landroid/view/InputEventReceiver;Landroid/view/ViewRootImpl$WindowInputEventReceiver;
HSPLandroid/view/ViewRootImpl$InputStage;-><init>(Landroid/view/ViewRootImpl;Landroid/view/ViewRootImpl$InputStage;)V
HSPLandroid/view/ViewRootImpl$InputStage;->apply(Landroid/view/ViewRootImpl$QueuedInputEvent;I)V+]Landroid/view/ViewRootImpl$InputStage;megamorphic_types
@@ -20395,7 +20382,6 @@
HSPLandroid/widget/OverScroller$SplineOverScroller;->fling(IIIII)V
HSPLandroid/widget/OverScroller$SplineOverScroller;->getSplineDeceleration(I)D
HSPLandroid/widget/OverScroller$SplineOverScroller;->getSplineFlingDistance(I)D
-HSPLandroid/widget/OverScroller$SplineOverScroller;->getSplineFlingDuration(I)I
HSPLandroid/widget/OverScroller$SplineOverScroller;->onEdgeReached()V
HSPLandroid/widget/OverScroller$SplineOverScroller;->springback(III)Z
HSPLandroid/widget/OverScroller$SplineOverScroller;->startScroll(III)V
@@ -22568,10 +22554,7 @@
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker$1;->onIsNonStrongBiometricAllowedChanged(ZI)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker$1;->onStrongAuthRequiredChanged(II)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker$H;->handleMessage(Landroid/os/Message;)V
-HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;-><init>(Landroid/content/Context;)V
-HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;-><init>(Landroid/content/Context;Landroid/os/Looper;)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->getStrongAuthForUser(I)I+]Landroid/util/SparseIntArray;Landroid/util/SparseIntArray;
-HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->getStub()Landroid/app/trust/IStrongAuthTracker$Stub;
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->handleIsNonStrongBiometricAllowedChanged(ZI)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->handleStrongAuthRequiredChanged(II)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->isNonStrongBiometricAllowedAfterIdleTimeout(I)Z
diff --git a/core/api/current.txt b/core/api/current.txt
index a7293f1..d9753ab 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -120,6 +120,7 @@
field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field @Deprecated public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
field public static final String QUERY_ALL_PACKAGES = "android.permission.QUERY_ALL_PACKAGES";
+ field public static final String READ_BASIC_PHONE_STATE = "android.permission.READ_BASIC_PHONE_STATE";
field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
@@ -9023,6 +9024,72 @@
field public static final int TELEPHONY = 4194304; // 0x400000
}
+ public final class BluetoothCodecConfig implements android.os.Parcelable {
+ ctor public BluetoothCodecConfig(int);
+ method public int describeContents();
+ method public int getBitsPerSample();
+ method public int getChannelMode();
+ method public int getCodecPriority();
+ method public long getCodecSpecific1();
+ method public long getCodecSpecific2();
+ method public long getCodecSpecific3();
+ method public long getCodecSpecific4();
+ method public int getCodecType();
+ method public static int getMaxCodecType();
+ method public int getSampleRate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BITS_PER_SAMPLE_16 = 1; // 0x1
+ field public static final int BITS_PER_SAMPLE_24 = 2; // 0x2
+ field public static final int BITS_PER_SAMPLE_32 = 4; // 0x4
+ field public static final int BITS_PER_SAMPLE_NONE = 0; // 0x0
+ field public static final int CHANNEL_MODE_MONO = 1; // 0x1
+ field public static final int CHANNEL_MODE_NONE = 0; // 0x0
+ field public static final int CHANNEL_MODE_STEREO = 2; // 0x2
+ field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0
+ field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff
+ field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecConfig> CREATOR;
+ field public static final int SAMPLE_RATE_176400 = 16; // 0x10
+ field public static final int SAMPLE_RATE_192000 = 32; // 0x20
+ field public static final int SAMPLE_RATE_44100 = 1; // 0x1
+ field public static final int SAMPLE_RATE_48000 = 2; // 0x2
+ field public static final int SAMPLE_RATE_88200 = 4; // 0x4
+ field public static final int SAMPLE_RATE_96000 = 8; // 0x8
+ field public static final int SAMPLE_RATE_NONE = 0; // 0x0
+ field public static final int SOURCE_CODEC_TYPE_AAC = 1; // 0x1
+ field public static final int SOURCE_CODEC_TYPE_APTX = 2; // 0x2
+ field public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; // 0x3
+ field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240
+ field public static final int SOURCE_CODEC_TYPE_LDAC = 4; // 0x4
+ field public static final int SOURCE_CODEC_TYPE_SBC = 0; // 0x0
+ }
+
+ public static final class BluetoothCodecConfig.Builder {
+ ctor public BluetoothCodecConfig.Builder();
+ method @NonNull public android.bluetooth.BluetoothCodecConfig build();
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setBitsPerSample(int);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setChannelMode(int);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecPriority(int);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific1(long);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific2(long);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific3(long);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific4(long);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecType(int);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setSampleRate(int);
+ }
+
+ public final class BluetoothCodecStatus implements android.os.Parcelable {
+ ctor public BluetoothCodecStatus(@Nullable android.bluetooth.BluetoothCodecConfig, @Nullable java.util.List<android.bluetooth.BluetoothCodecConfig>, @Nullable java.util.List<android.bluetooth.BluetoothCodecConfig>);
+ method public int describeContents();
+ method @Nullable public android.bluetooth.BluetoothCodecConfig getCodecConfig();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getCodecsLocalCapabilities();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getCodecsSelectableCapabilities();
+ method public boolean isCodecConfigSelectable(@Nullable android.bluetooth.BluetoothCodecConfig);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecStatus> CREATOR;
+ field public static final String EXTRA_CODEC_STATUS = "android.bluetooth.extra.CODEC_STATUS";
+ }
+
public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
method public void close();
method protected void finalize();
@@ -9252,7 +9319,8 @@
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int notifyCharacteristicChanged(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothGattCharacteristic, boolean, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void readPhy(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeService(android.bluetooth.BluetoothGattService);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
@@ -9452,6 +9520,20 @@
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
}
+ public final class BluetoothLeAudioCodecConfig {
+ method @NonNull public String getCodecName();
+ method public int getCodecType();
+ method public static int getMaxCodecType();
+ field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240
+ field public static final int SOURCE_CODEC_TYPE_LC3 = 0; // 0x0
+ }
+
+ public static final class BluetoothLeAudioCodecConfig.Builder {
+ ctor public BluetoothLeAudioCodecConfig.Builder();
+ method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig build();
+ method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setCodecType(int);
+ }
+
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
@@ -31469,6 +31551,7 @@
method public int dataPosition();
method public int dataSize();
method public void enforceInterface(@NonNull String);
+ method public void enforceNoDataAvail();
method public boolean hasFileDescriptors();
method public boolean hasFileDescriptors(int, int);
method public byte[] marshall();
@@ -31507,16 +31590,17 @@
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 readParcelable(@Nullable ClassLoader, @NonNull Class<T>);
+ method @Deprecated @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
method @Nullable public <T> T[] readParcelableArray(@Nullable ClassLoader, @NonNull Class<T>);
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 @Deprecated @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
+ method @NonNull public <T> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader, @NonNull Class<T>);
method @Nullable public android.os.PersistableBundle readPersistableBundle();
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
method @Deprecated @Nullable public java.io.Serializable readSerializable();
- method @Nullable public <T extends java.io.Serializable> T readSerializable(@Nullable ClassLoader, @NonNull Class<T>);
+ method @Nullable public <T> T readSerializable(@Nullable ClassLoader, @NonNull Class<T>);
method @NonNull public android.util.Size readSize();
method @NonNull public android.util.SizeF readSizeF();
method @Deprecated @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);
@@ -39985,6 +40069,7 @@
field public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final String EXTRA_IS_RTT_AUDIO_PRESENT = "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
field public static final String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+ field public static final String EXTRA_LAST_KNOWN_CELL_IDENTITY = "android.telecom.extra.LAST_KNOWN_CELL_IDENTITY";
field public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
field public static final int PROPERTY_ASSISTED_DIALING = 512; // 0x200
field public static final int PROPERTY_CROSS_SIM = 8192; // 0x2000
@@ -42720,11 +42805,11 @@
method public int getCarrierIdFromSimMccMnc();
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.telephony.CellLocation getCellLocation();
method public int getDataActivity();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getDataNetworkType();
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public int getDataNetworkType();
method public int getDataState();
method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId();
method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public String getDeviceSoftwareVersion();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
@@ -42777,22 +42862,22 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVisualVoicemailPackageName();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType();
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public int getVoiceNetworkType();
method @Nullable public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
method public boolean hasIccCard();
- method @Deprecated public boolean iccCloseLogicalChannel(int);
- method @Deprecated public byte[] iccExchangeSimIO(int, int, int, int, int, String);
+ method public boolean iccCloseLogicalChannel(int);
+ method public byte[] iccExchangeSimIO(int, int, int, int, int, String);
method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String);
- method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int);
- method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
- method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
+ method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int);
+ method public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
+ method public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
method public boolean isDataCapable();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabled();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataConnectionAllowed();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataEnabledForReason(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataRoamingEnabled();
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();
@@ -42811,7 +42896,7 @@
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
method public void sendDialerSpecialCode(String);
- method @Deprecated public String sendEnvelopeWithStatus(String);
+ method public String sendEnvelopeWithStatus(String);
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallComposerStatus(int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 84a4a44..cd1fef9 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12055,10 +12055,10 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
@@ -12884,6 +12884,7 @@
method @NonNull public java.util.Set<android.telephony.ims.FeatureTagState> getDeregisteredFeatureTags();
method @NonNull public java.util.Set<android.telephony.ims.FeatureTagState> getDeregisteringFeatureTags();
method @NonNull public java.util.Set<java.lang.String> getRegisteredFeatureTags();
+ method @NonNull public java.util.Set<java.lang.String> getRegisteringFeatureTags();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.DelegateRegistrationState> CREATOR;
field public static final int DEREGISTERED_REASON_NOT_PROVISIONED = 1; // 0x1
@@ -12891,8 +12892,10 @@
field public static final int DEREGISTERED_REASON_UNKNOWN = 0; // 0x0
field public static final int DEREGISTERING_REASON_DESTROY_PENDING = 6; // 0x6
field public static final int DEREGISTERING_REASON_FEATURE_TAGS_CHANGING = 5; // 0x5
+ field public static final int DEREGISTERING_REASON_LOSING_PDN = 7; // 0x7
field public static final int DEREGISTERING_REASON_PDN_CHANGE = 3; // 0x3
field public static final int DEREGISTERING_REASON_PROVISIONING_CHANGE = 4; // 0x4
+ field public static final int DEREGISTERING_REASON_UNSPECIFIED = 8; // 0x8
}
public static final class DelegateRegistrationState.Builder {
@@ -12901,6 +12904,7 @@
method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addDeregisteringFeatureTag(@NonNull String, int);
method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteredFeatureTag(@NonNull String);
method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteredFeatureTags(@NonNull java.util.Set<java.lang.String>);
+ method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteringFeatureTags(@NonNull java.util.Set<java.lang.String>);
method @NonNull public android.telephony.ims.DelegateRegistrationState build();
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 6154b71..14be921 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -51,7 +51,6 @@
import android.content.Attributable;
import android.content.AttributionSource;
import android.content.Context;
-import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
@@ -59,7 +58,6 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
-import android.os.SynchronousResultReceiver;
import android.os.SystemProperties;
import android.util.Log;
import android.util.Pair;
@@ -82,7 +80,6 @@
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
@@ -2424,38 +2421,6 @@
}
/**
- * Return the record of {@link BluetoothActivityEnergyInfo} object that
- * has the activity and energy info. This can be used to ascertain what
- * the controller has been up to, since the last sample.
- *
- * @param updateType Type of info, cached vs refreshed.
- * @return a record with {@link BluetoothActivityEnergyInfo} or null if report is unavailable or
- * unsupported
- * @hide
- * @deprecated use the asynchronous {@link #requestControllerActivityEnergyInfo(ResultReceiver)}
- * instead.
- */
- @Deprecated
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
- SynchronousResultReceiver receiver = new SynchronousResultReceiver();
- requestControllerActivityEnergyInfo(receiver);
- try {
- SynchronousResultReceiver.Result result = receiver.awaitResult(1000);
- if (result.bundle != null) {
- return result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY);
- }
- } catch (TimeoutException e) {
- Log.e(TAG, "getControllerActivityEnergyInfo timed out");
- }
- return null;
- }
-
- /**
* Request the record of {@link BluetoothActivityEnergyInfo} object that
* has the activity and energy info. This can be used to ascertain what
* the controller has been up to, since the last sample.
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 1d0bf97..9a4151a 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -29,16 +29,14 @@
/**
* Represents the codec configuration for a Bluetooth A2DP source device.
+ * <p>Contains the source codec type, the codec priority, the codec sample
+ * rate, the codec bits per sample, and the codec channel mode.
+ * <p>The source codec type values are the same as those supported by the
+ * device hardware.
*
* {@see BluetoothA2dp}
- *
- * {@hide}
*/
public final class BluetoothCodecConfig implements Parcelable {
- // Add an entry for each source codec here.
- // NOTE: The values should be same as those listed in the following file:
- // hardware/libhardware/include/hardware/bt_av.h
-
/** @hide */
@IntDef(prefix = "SOURCE_CODEC_TYPE_", value = {
SOURCE_CODEC_TYPE_SBC,
@@ -46,33 +44,49 @@
SOURCE_CODEC_TYPE_APTX,
SOURCE_CODEC_TYPE_APTX_HD,
SOURCE_CODEC_TYPE_LDAC,
- SOURCE_CODEC_TYPE_MAX,
SOURCE_CODEC_TYPE_INVALID
})
@Retention(RetentionPolicy.SOURCE)
public @interface SourceCodecType {}
- @UnsupportedAppUsage
+ /**
+ * Source codec type SBC. This is the mandatory source codec
+ * type.
+ */
public static final int SOURCE_CODEC_TYPE_SBC = 0;
- @UnsupportedAppUsage
+ /**
+ * Source codec type AAC.
+ */
public static final int SOURCE_CODEC_TYPE_AAC = 1;
- @UnsupportedAppUsage
+ /**
+ * Source codec type APTX.
+ */
public static final int SOURCE_CODEC_TYPE_APTX = 2;
- @UnsupportedAppUsage
+ /**
+ * Source codec type APTX HD.
+ */
public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
- @UnsupportedAppUsage
+ /**
+ * Source codec type LDAC.
+ */
public static final int SOURCE_CODEC_TYPE_LDAC = 4;
- @UnsupportedAppUsage
- public static final int SOURCE_CODEC_TYPE_MAX = 5;
-
- @UnsupportedAppUsage
+ /**
+ * Source codec type invalid. This is the default value used for codec
+ * type.
+ */
public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
+ /**
+ * Represents the count of valid source codec types. Can be accessed via
+ * {@link #getMaxCodecType}.
+ */
+ private static final int SOURCE_CODEC_TYPE_MAX = 5;
+
/** @hide */
@IntDef(prefix = "CODEC_PRIORITY_", value = {
CODEC_PRIORITY_DISABLED,
@@ -82,16 +96,24 @@
@Retention(RetentionPolicy.SOURCE)
public @interface CodecPriority {}
- @UnsupportedAppUsage
+ /**
+ * Codec priority disabled.
+ * Used to indicate that this codec is disabled and should not be used.
+ */
public static final int CODEC_PRIORITY_DISABLED = -1;
- @UnsupportedAppUsage
+ /**
+ * Codec priority default.
+ * Default value used for codec priority.
+ */
public static final int CODEC_PRIORITY_DEFAULT = 0;
- @UnsupportedAppUsage
+ /**
+ * Codec priority highest.
+ * Used to indicate the highest priority a codec can have.
+ */
public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
-
/** @hide */
@IntDef(prefix = "SAMPLE_RATE_", value = {
SAMPLE_RATE_NONE,
@@ -105,28 +127,42 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SampleRate {}
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 0 Hz. Default value used for
+ * codec sample rate.
+ */
public static final int SAMPLE_RATE_NONE = 0;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 44100 Hz.
+ */
public static final int SAMPLE_RATE_44100 = 0x1 << 0;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 48000 Hz.
+ */
public static final int SAMPLE_RATE_48000 = 0x1 << 1;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 88200 Hz.
+ */
public static final int SAMPLE_RATE_88200 = 0x1 << 2;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 96000 Hz.
+ */
public static final int SAMPLE_RATE_96000 = 0x1 << 3;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 176400 Hz.
+ */
public static final int SAMPLE_RATE_176400 = 0x1 << 4;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 192000 Hz.
+ */
public static final int SAMPLE_RATE_192000 = 0x1 << 5;
-
/** @hide */
@IntDef(prefix = "BITS_PER_SAMPLE_", value = {
BITS_PER_SAMPLE_NONE,
@@ -137,19 +173,27 @@
@Retention(RetentionPolicy.SOURCE)
public @interface BitsPerSample {}
- @UnsupportedAppUsage
+ /**
+ * Codec bits per sample 0. Default value of the codec
+ * bits per sample.
+ */
public static final int BITS_PER_SAMPLE_NONE = 0;
- @UnsupportedAppUsage
+ /**
+ * Codec bits per sample 16.
+ */
public static final int BITS_PER_SAMPLE_16 = 0x1 << 0;
- @UnsupportedAppUsage
+ /**
+ * Codec bits per sample 24.
+ */
public static final int BITS_PER_SAMPLE_24 = 0x1 << 1;
- @UnsupportedAppUsage
+ /**
+ * Codec bits per sample 32.
+ */
public static final int BITS_PER_SAMPLE_32 = 0x1 << 2;
-
/** @hide */
@IntDef(prefix = "CHANNEL_MODE_", value = {
CHANNEL_MODE_NONE,
@@ -159,13 +203,20 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ChannelMode {}
- @UnsupportedAppUsage
+ /**
+ * Codec channel mode NONE. Default value of the
+ * codec channel mode.
+ */
public static final int CHANNEL_MODE_NONE = 0;
- @UnsupportedAppUsage
+ /**
+ * Codec channel mode MONO.
+ */
public static final int CHANNEL_MODE_MONO = 0x1 << 0;
- @UnsupportedAppUsage
+ /**
+ * Codec channel mode STEREO.
+ */
public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
private final @SourceCodecType int mCodecType;
@@ -178,6 +229,21 @@
private final long mCodecSpecific3;
private final long mCodecSpecific4;
+ /**
+ * Creates a new BluetoothCodecConfig.
+ *
+ * @param codecType the source codec type
+ * @param codecPriority the priority of this codec
+ * @param sampleRate the codec sample rate
+ * @param bitsPerSample the bits per sample of this codec
+ * @param channelMode the channel mode of this codec
+ * @param codecSpecific1 the specific value 1
+ * @param codecSpecific2 the specific value 2
+ * @param codecSpecific3 the specific value 3
+ * @param codecSpecific4 the specific value 4
+ * values to 0.
+ * @hide
+ */
@UnsupportedAppUsage
public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority,
@SampleRate int sampleRate, @BitsPerSample int bitsPerSample,
@@ -195,17 +261,34 @@
mCodecSpecific4 = codecSpecific4;
}
- @UnsupportedAppUsage
+ /**
+ * Creates a new BluetoothCodecConfig.
+ * <p> By default, the codec priority will be set
+ * to {@link BluetoothCodecConfig#CODEC_PRIORITY_DEFAULT}, the sample rate to
+ * {@link BluetoothCodecConfig#SAMPLE_RATE_NONE}, the bits per sample to
+ * {@link BluetoothCodecConfig#BITS_PER_SAMPLE_NONE}, the channel mode to
+ * {@link BluetoothCodecConfig#CHANNEL_MODE_NONE}, and all the codec specific
+ * values to 0.
+ *
+ * @param codecType the source codec type
+ */
public BluetoothCodecConfig(@SourceCodecType int codecType) {
- mCodecType = codecType;
- mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
- mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
- mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
- mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE;
- mCodecSpecific1 = 0;
- mCodecSpecific2 = 0;
- mCodecSpecific3 = 0;
- mCodecSpecific4 = 0;
+ this(codecType, BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_NONE,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_NONE,
+ BluetoothCodecConfig.CHANNEL_MODE_NONE, 0, 0, 0, 0);
+ }
+
+ private BluetoothCodecConfig(Parcel in) {
+ mCodecType = in.readInt();
+ mCodecPriority = in.readInt();
+ mSampleRate = in.readInt();
+ mBitsPerSample = in.readInt();
+ mChannelMode = in.readInt();
+ mCodecSpecific1 = in.readLong();
+ mCodecSpecific2 = in.readLong();
+ mCodecSpecific3 = in.readLong();
+ mCodecSpecific4 = in.readLong();
}
@Override
@@ -226,10 +309,8 @@
}
/**
- * Returns a hash based on the config values
- *
- * @return a hash based on the config values
- * @hide
+ * Returns a hash representation of this BluetoothCodecConfig
+ * based on all the config values.
*/
@Override
public int hashCode() {
@@ -239,32 +320,24 @@
}
/**
- * Checks whether the object contains valid codec configuration.
- *
- * @return true if the object contains valid codec configuration, otherwise false.
- * @hide
- */
- public boolean isValid() {
- return (mSampleRate != SAMPLE_RATE_NONE)
- && (mBitsPerSample != BITS_PER_SAMPLE_NONE)
- && (mChannelMode != CHANNEL_MODE_NONE);
- }
-
- /**
* Adds capability string to an existing string.
*
- * @param prevStr the previous string with the capabilities. Can be a null pointer.
- * @param capStr the capability string to append to prevStr argument.
- * @return the result string in the form "prevStr|capStr".
+ * @param prevStr the previous string with the capabilities. Can be a {@code null} pointer
+ * @param capStr the capability string to append to prevStr argument
+ * @return the result string in the form "prevStr|capStr"
*/
- private static String appendCapabilityToString(String prevStr,
- String capStr) {
+ private static String appendCapabilityToString(@Nullable String prevStr,
+ @NonNull String capStr) {
if (prevStr == null) {
return capStr;
}
return prevStr + "|" + capStr;
}
+ /**
+ * Returns a {@link String} that describes each BluetoothCodecConfig parameter
+ * current value.
+ */
@Override
public String toString() {
String sampleRateStr = null;
@@ -331,8 +404,6 @@
}
/**
- * Always returns 0
- *
* @return 0
* @hide
*/
@@ -344,20 +415,7 @@
public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecConfig> CREATOR =
new Parcelable.Creator<BluetoothCodecConfig>() {
public BluetoothCodecConfig createFromParcel(Parcel in) {
- final int codecType = in.readInt();
- final int codecPriority = in.readInt();
- final int sampleRate = in.readInt();
- final int bitsPerSample = in.readInt();
- final int channelMode = in.readInt();
- final long codecSpecific1 = in.readLong();
- final long codecSpecific2 = in.readLong();
- final long codecSpecific3 = in.readLong();
- final long codecSpecific4 = in.readLong();
- return new BluetoothCodecConfig(codecType, codecPriority,
- sampleRate, bitsPerSample,
- channelMode, codecSpecific1,
- codecSpecific2, codecSpecific3,
- codecSpecific4);
+ return new BluetoothCodecConfig(in);
}
public BluetoothCodecConfig[] newArray(int size) {
@@ -368,8 +426,8 @@
/**
* Flattens the object to a parcel
*
- * @param out The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written.
+ * @param out The Parcel in which the object should be written
+ * @param flags Additional flags about how the object should be written
*
* @hide
*/
@@ -387,9 +445,8 @@
}
/**
- * Gets the codec name.
- *
- * @return the codec name
+ * Returns the codec name converted to {@link String}.
+ * @hide
*/
public @NonNull String getCodecName() {
switch (mCodecType) {
@@ -412,137 +469,100 @@
}
/**
- * Gets the codec type.
- * See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
- *
- * @return the codec type
+ * Returns the source codec type of this config.
*/
- @UnsupportedAppUsage
public @SourceCodecType int getCodecType() {
return mCodecType;
}
/**
+ * Returns the valid codec types count.
+ */
+ public static int getMaxCodecType() {
+ return SOURCE_CODEC_TYPE_MAX;
+ }
+
+ /**
* Checks whether the codec is mandatory.
+ * <p> The actual mandatory codec type for Android Bluetooth audio is SBC.
+ * See {@link #SOURCE_CODEC_TYPE_SBC}.
*
- * @return true if the codec is mandatory, otherwise false.
+ * @return {@code true} if the codec is mandatory, {@code false} otherwise
+ * @hide
*/
public boolean isMandatoryCodec() {
return mCodecType == SOURCE_CODEC_TYPE_SBC;
}
/**
- * Gets the codec selection priority.
- * The codec selection priority is relative to other codecs: larger value
- * means higher priority. If 0, reset to default.
- *
- * @return the codec priority
+ * Returns the codec selection priority.
+ * <p>The codec selection priority is relative to other codecs: larger value
+ * means higher priority.
*/
- @UnsupportedAppUsage
public @CodecPriority int getCodecPriority() {
return mCodecPriority;
}
/**
* Sets the codec selection priority.
- * The codec selection priority is relative to other codecs: larger value
- * means higher priority. If 0, reset to default.
+ * <p>The codec selection priority is relative to other codecs: larger value
+ * means higher priority.
*
- * @param codecPriority the codec priority
+ * @param codecPriority the priority this codec should have
* @hide
*/
- @UnsupportedAppUsage
public void setCodecPriority(@CodecPriority int codecPriority) {
mCodecPriority = codecPriority;
}
/**
- * Gets the codec sample rate. The value can be a bitmask with all
- * supported sample rates:
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_48000} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_88200} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_96000} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_176400} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_192000}
- *
- * @return the codec sample rate
+ * Returns the codec sample rate. The value can be a bitmask with all
+ * supported sample rates.
*/
- @UnsupportedAppUsage
public @SampleRate int getSampleRate() {
return mSampleRate;
}
/**
- * Gets the codec bits per sample. The value can be a bitmask with all
- * bits per sample supported:
- * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
- * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
- * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_24} or
- * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_32}
- *
- * @return the codec bits per sample
+ * Returns the codec bits per sample. The value can be a bitmask with all
+ * bits per sample supported.
*/
- @UnsupportedAppUsage
public @BitsPerSample int getBitsPerSample() {
return mBitsPerSample;
}
/**
- * Gets the codec channel mode. The value can be a bitmask with all
- * supported channel modes:
- * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
- * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
- * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO}
- *
- * @return the codec channel mode
- * @hide
+ * Returns the codec channel mode. The value can be a bitmask with all
+ * supported channel modes.
*/
- @UnsupportedAppUsage
public @ChannelMode int getChannelMode() {
return mChannelMode;
}
/**
- * Gets a codec specific value1.
- *
- * @return a codec specific value1.
+ * Returns the codec specific value1.
*/
- @UnsupportedAppUsage
public long getCodecSpecific1() {
return mCodecSpecific1;
}
/**
- * Gets a codec specific value2.
- *
- * @return a codec specific value2
- * @hide
+ * Returns the codec specific value2.
*/
- @UnsupportedAppUsage
public long getCodecSpecific2() {
return mCodecSpecific2;
}
/**
- * Gets a codec specific value3.
- *
- * @return a codec specific value3
- * @hide
+ * Returns the codec specific value3.
*/
- @UnsupportedAppUsage
public long getCodecSpecific3() {
return mCodecSpecific3;
}
/**
- * Gets a codec specific value4.
- *
- * @return a codec specific value4
- * @hide
+ * Returns the codec specific value4.
*/
- @UnsupportedAppUsage
public long getCodecSpecific4() {
return mCodecSpecific4;
}
@@ -551,7 +571,7 @@
* Checks whether a value set presented by a bitmask has zero or single bit
*
* @param valueSet the value set presented by a bitmask
- * @return true if the valueSet contains zero or single bit, otherwise false.
+ * @return {@code true} if the valueSet contains zero or single bit, {@code false} otherwise
* @hide
*/
private static boolean hasSingleBit(int valueSet) {
@@ -559,9 +579,7 @@
}
/**
- * Checks whether the object contains none or single sample rate.
- *
- * @return true if the object contains none or single sample rate, otherwise false.
+ * Returns whether the object contains none or single sample rate.
* @hide
*/
public boolean hasSingleSampleRate() {
@@ -569,9 +587,7 @@
}
/**
- * Checks whether the object contains none or single bits per sample.
- *
- * @return true if the object contains none or single bits per sample, otherwise false.
+ * Returns whether the object contains none or single bits per sample.
* @hide
*/
public boolean hasSingleBitsPerSample() {
@@ -579,9 +595,7 @@
}
/**
- * Checks whether the object contains none or single channel mode.
- *
- * @return true if the object contains none or single channel mode, otherwise false.
+ * Returns whether the object contains none or single channel mode.
* @hide
*/
public boolean hasSingleChannelMode() {
@@ -589,10 +603,10 @@
}
/**
- * Checks whether the audio feeding parameters are same.
+ * Checks whether the audio feeding parameters are the same.
*
* @param other the codec config to compare against
- * @return true if the audio feeding parameters are same, otherwise false
+ * @return {@code true} if the audio feeding parameters are same, {@code false} otherwise
* @hide
*/
public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
@@ -606,7 +620,7 @@
* Any parameters with NONE value will be considered to be a wildcard matching.
*
* @param other the codec config to compare against
- * @return true if the audio feeding parameters are similar, otherwise false.
+ * @return {@code true} if the audio feeding parameters are similar, {@code false} otherwise
* @hide
*/
public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) {
@@ -614,18 +628,18 @@
return false;
}
int sampleRate = other.mSampleRate;
- if (mSampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE
- || sampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE) {
+ if (mSampleRate == SAMPLE_RATE_NONE
+ || sampleRate == SAMPLE_RATE_NONE) {
sampleRate = mSampleRate;
}
int bitsPerSample = other.mBitsPerSample;
- if (mBitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE
- || bitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
+ if (mBitsPerSample == BITS_PER_SAMPLE_NONE
+ || bitsPerSample == BITS_PER_SAMPLE_NONE) {
bitsPerSample = mBitsPerSample;
}
int channelMode = other.mChannelMode;
- if (mChannelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE
- || channelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE) {
+ if (mChannelMode == CHANNEL_MODE_NONE
+ || channelMode == CHANNEL_MODE_NONE) {
channelMode = mChannelMode;
}
return sameAudioFeedingParameters(new BluetoothCodecConfig(
@@ -636,25 +650,158 @@
/**
* Checks whether the codec specific parameters are the same.
+ * <p> Currently, only AAC VBR and LDAC Playback Quality on CodecSpecific1
+ * are compared.
*
* @param other the codec config to compare against
- * @return true if the codec specific parameters are the same, otherwise false.
+ * @return {@code true} if the codec specific parameters are the same, {@code false} otherwise
* @hide
*/
public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) {
if (other == null && mCodecType != other.mCodecType) {
return false;
}
- // Currently we only care about the AAC VBR and LDAC Playback Quality at CodecSpecific1
switch (mCodecType) {
case SOURCE_CODEC_TYPE_AAC:
case SOURCE_CODEC_TYPE_LDAC:
if (mCodecSpecific1 != other.mCodecSpecific1) {
return false;
}
- // fall through
default:
return true;
}
}
+
+ /**
+ * Builder for {@link BluetoothCodecConfig}.
+ * <p> By default, the codec type will be set to
+ * {@link BluetoothCodecConfig#SOURCE_CODEC_TYPE_INVALID}, the codec priority
+ * to {@link BluetoothCodecConfig#CODEC_PRIORITY_DEFAULT}, the sample rate to
+ * {@link BluetoothCodecConfig#SAMPLE_RATE_NONE}, the bits per sample to
+ * {@link BluetoothCodecConfig#BITS_PER_SAMPLE_NONE}, the channel mode to
+ * {@link BluetoothCodecConfig#CHANNEL_MODE_NONE}, and all the codec specific
+ * values to 0.
+ */
+ public static final class Builder {
+ private int mCodecType = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
+ private int mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
+ private int mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
+ private int mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
+ private int mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE;
+ private long mCodecSpecific1 = 0;
+ private long mCodecSpecific2 = 0;
+ private long mCodecSpecific3 = 0;
+ private long mCodecSpecific4 = 0;
+
+ /**
+ * Set codec type for Bluetooth codec config.
+ *
+ * @param codecType of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecType(@SourceCodecType int codecType) {
+ mCodecType = codecType;
+ return this;
+ }
+
+ /**
+ * Set codec priority for Bluetooth codec config.
+ *
+ * @param codecPriority of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecPriority(@CodecPriority int codecPriority) {
+ mCodecPriority = codecPriority;
+ return this;
+ }
+
+ /**
+ * Set sample rate for Bluetooth codec config.
+ *
+ * @param sampleRate of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setSampleRate(@SampleRate int sampleRate) {
+ mSampleRate = sampleRate;
+ return this;
+ }
+
+ /**
+ * Set the bits per sample for Bluetooth codec config.
+ *
+ * @param bitsPerSample of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setBitsPerSample(@BitsPerSample int bitsPerSample) {
+ mBitsPerSample = bitsPerSample;
+ return this;
+ }
+
+ /**
+ * Set the channel mode for Bluetooth codec config.
+ *
+ * @param channelMode of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setChannelMode(@ChannelMode int channelMode) {
+ mChannelMode = channelMode;
+ return this;
+ }
+
+ /**
+ * Set the first codec specific values for Bluetooth codec config.
+ *
+ * @param codecSpecific1 codec specific value or 0 if default
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecSpecific1(long codecSpecific1) {
+ mCodecSpecific1 = codecSpecific1;
+ return this;
+ }
+
+ /**
+ * Set the second codec specific values for Bluetooth codec config.
+ *
+ * @param codecSpecific2 codec specific value or 0 if default
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecSpecific2(long codecSpecific2) {
+ mCodecSpecific2 = codecSpecific2;
+ return this;
+ }
+
+ /**
+ * Set the third codec specific values for Bluetooth codec config.
+ *
+ * @param codecSpecific3 codec specific value or 0 if default
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecSpecific3(long codecSpecific3) {
+ mCodecSpecific3 = codecSpecific3;
+ return this;
+ }
+
+ /**
+ * Set the fourth codec specific values for Bluetooth codec config.
+ *
+ * @param codecSpecific4 codec specific value or 0 if default
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecSpecific4(long codecSpecific4) {
+ mCodecSpecific4 = codecSpecific4;
+ return this;
+ }
+
+ /**
+ * Build {@link BluetoothCodecConfig}.
+ * @return new BluetoothCodecConfig built
+ */
+ public @NonNull BluetoothCodecConfig build() {
+ return new BluetoothCodecConfig(mCodecType, mCodecPriority,
+ mSampleRate, mBitsPerSample,
+ mChannelMode, mCodecSpecific1,
+ mCodecSpecific2, mCodecSpecific3,
+ mCodecSpecific4);
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
index 7764ebe..02606fe 100644
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -16,12 +16,13 @@
package android.bluetooth;
+import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -29,8 +30,6 @@
* A2DP source device.
*
* {@see BluetoothA2dp}
- *
- * {@hide}
*/
public final class BluetoothCodecStatus implements Parcelable {
/**
@@ -39,22 +38,27 @@
* This extra represents the current codec status of the A2DP
* profile.
*/
- @UnsupportedAppUsage
public static final String EXTRA_CODEC_STATUS =
"android.bluetooth.extra.CODEC_STATUS";
private final @Nullable BluetoothCodecConfig mCodecConfig;
- private final BluetoothCodecConfig[] mCodecsLocalCapabilities;
- private final BluetoothCodecConfig[] mCodecsSelectableCapabilities;
+ private final @Nullable List<BluetoothCodecConfig> mCodecsLocalCapabilities;
+ private final @Nullable List<BluetoothCodecConfig> mCodecsSelectableCapabilities;
public BluetoothCodecStatus(@Nullable BluetoothCodecConfig codecConfig,
- @Nullable BluetoothCodecConfig[] codecsLocalCapabilities,
- @Nullable BluetoothCodecConfig[] codecsSelectableCapabilities) {
+ @Nullable List<BluetoothCodecConfig> codecsLocalCapabilities,
+ @Nullable List<BluetoothCodecConfig> codecsSelectableCapabilities) {
mCodecConfig = codecConfig;
mCodecsLocalCapabilities = codecsLocalCapabilities;
mCodecsSelectableCapabilities = codecsSelectableCapabilities;
}
+ private BluetoothCodecStatus(Parcel in) {
+ mCodecConfig = in.readTypedObject(BluetoothCodecConfig.CREATOR);
+ mCodecsLocalCapabilities = in.createTypedArrayList(BluetoothCodecConfig.CREATOR);
+ mCodecsSelectableCapabilities = in.createTypedArrayList(BluetoothCodecConfig.CREATOR);
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (o instanceof BluetoothCodecStatus) {
@@ -68,26 +72,25 @@
}
/**
- * Checks whether two arrays of capabilities contain same capabilities.
- * The order of the capabilities in each array is ignored.
+ * Checks whether two lists of capabilities contain same capabilities.
+ * The order of the capabilities in each list is ignored.
*
- * @param c1 the first array of capabilities to compare
- * @param c2 the second array of capabilities to compare
- * @return true if both arrays contain same capabilities
- * @hide
+ * @param c1 the first list of capabilities to compare
+ * @param c2 the second list of capabilities to compare
+ * @return {@code true} if both lists contain same capabilities
*/
- public static boolean sameCapabilities(BluetoothCodecConfig[] c1,
- BluetoothCodecConfig[] c2) {
+ private static boolean sameCapabilities(@Nullable List<BluetoothCodecConfig> c1,
+ @Nullable List<BluetoothCodecConfig> c2) {
if (c1 == null) {
return (c2 == null);
}
if (c2 == null) {
return false;
}
- if (c1.length != c2.length) {
+ if (c1.size() != c2.size()) {
return false;
}
- return Arrays.asList(c1).containsAll(Arrays.asList(c2));
+ return c1.containsAll(c2);
}
/**
@@ -95,10 +98,9 @@
* Any parameters of the codec config with NONE value will be considered a wildcard matching.
*
* @param codecConfig the codec config to compare against
- * @return true if the codec config matches, otherwise false
- * @hide
+ * @return {@code true} if the codec config matches, {@code false} otherwise
*/
- public boolean isCodecConfigSelectable(BluetoothCodecConfig codecConfig) {
+ public boolean isCodecConfigSelectable(@Nullable BluetoothCodecConfig codecConfig) {
if (codecConfig == null || !codecConfig.hasSingleSampleRate()
|| !codecConfig.hasSingleBitsPerSample() || !codecConfig.hasSingleChannelMode()) {
return false;
@@ -128,10 +130,7 @@
}
/**
- * Returns a hash based on the codec config and local capabilities
- *
- * @return a hash based on the config values
- * @hide
+ * Returns a hash based on the codec config and local capabilities.
*/
@Override
public int hashCode() {
@@ -139,17 +138,19 @@
mCodecsLocalCapabilities);
}
+ /**
+ * Returns a {@link String} that describes each BluetoothCodecStatus parameter
+ * current value.
+ */
@Override
public String toString() {
return "{mCodecConfig:" + mCodecConfig
- + ",mCodecsLocalCapabilities:" + Arrays.toString(mCodecsLocalCapabilities)
- + ",mCodecsSelectableCapabilities:" + Arrays.toString(mCodecsSelectableCapabilities)
+ + ",mCodecsLocalCapabilities:" + mCodecsLocalCapabilities
+ + ",mCodecsSelectableCapabilities:" + mCodecsSelectableCapabilities
+ "}";
}
/**
- * Always returns 0
- *
* @return 0
* @hide
*/
@@ -161,16 +162,7 @@
public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecStatus> CREATOR =
new Parcelable.Creator<BluetoothCodecStatus>() {
public BluetoothCodecStatus createFromParcel(Parcel in) {
- final BluetoothCodecConfig codecConfig = in.readTypedObject(
- BluetoothCodecConfig.CREATOR);
- final BluetoothCodecConfig[] codecsLocalCapabilities = in.createTypedArray(
- BluetoothCodecConfig.CREATOR);
- final BluetoothCodecConfig[] codecsSelectableCapabilities = in.createTypedArray(
- BluetoothCodecConfig.CREATOR);
-
- return new BluetoothCodecStatus(codecConfig,
- codecsLocalCapabilities,
- codecsSelectableCapabilities);
+ return new BluetoothCodecStatus(in);
}
public BluetoothCodecStatus[] newArray(int size) {
@@ -179,47 +171,38 @@
};
/**
- * Flattens the object to a parcel
+ * Flattens the object to a parcel.
*
- * @param out The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written.
- *
- * @hide
+ * @param out The Parcel in which the object should be written
+ * @param flags Additional flags about how the object should be written
*/
@Override
- public void writeToParcel(Parcel out, int flags) {
+ public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeTypedObject(mCodecConfig, 0);
- out.writeTypedArray(mCodecsLocalCapabilities, 0);
- out.writeTypedArray(mCodecsSelectableCapabilities, 0);
+ out.writeTypedList(mCodecsLocalCapabilities);
+ out.writeTypedList(mCodecsSelectableCapabilities);
}
/**
- * Gets the current codec configuration.
- *
- * @return the current codec configuration
+ * Returns the current codec configuration.
*/
- @UnsupportedAppUsage
public @Nullable BluetoothCodecConfig getCodecConfig() {
return mCodecConfig;
}
/**
- * Gets the codecs local capabilities.
- *
- * @return an array with the codecs local capabilities
+ * Returns the codecs local capabilities.
*/
- @UnsupportedAppUsage
- public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() {
- return mCodecsLocalCapabilities;
+ public @NonNull List<BluetoothCodecConfig> getCodecsLocalCapabilities() {
+ return (mCodecsLocalCapabilities == null)
+ ? Collections.emptyList() : mCodecsLocalCapabilities;
}
/**
- * Gets the codecs selectable capabilities.
- *
- * @return an array with the codecs selectable capabilities
+ * Returns the codecs selectable capabilities.
*/
- @UnsupportedAppUsage
- public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
- return mCodecsSelectableCapabilities;
+ public @NonNull List<BluetoothCodecConfig> getCodecsSelectableCapabilities() {
+ return (mCodecsSelectableCapabilities == null)
+ ? Collections.emptyList() : mCodecsSelectableCapabilities;
}
}
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 3e799de..08e0178 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
@@ -26,6 +28,8 @@
import android.os.RemoteException;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -709,33 +713,85 @@
* notification
* @return true, if the notification has been triggered successfully
* @throws IllegalArgumentException
+ *
+ * @deprecated Use {@link BluetoothGattServer#notifyCharacteristicChanged(BluetoothDevice,
+ * BluetoothGattCharacteristic, boolean, byte[])} as this is not memory safe.
*/
+ @Deprecated
@RequiresLegacyBluetoothPermission
@RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean notifyCharacteristicChanged(BluetoothDevice device,
BluetoothGattCharacteristic characteristic, boolean confirm) {
+ return notifyCharacteristicChanged(device, characteristic, confirm,
+ characteristic.getValue()) == BluetoothStatusCodes.SUCCESS;
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ BluetoothStatusCodes.SUCCESS,
+ BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
+ BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION,
+ BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED,
+ BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
+ BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED,
+ BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY,
+ BluetoothStatusCodes.ERROR_UNKNOWN
+ })
+ public @interface NotifyCharacteristicReturnValues{}
+
+ /**
+ * Send a notification or indication that a local characteristic has been
+ * updated.
+ *
+ * <p>A notification or indication is sent to the remote device to signal
+ * that the characteristic has been updated. This function should be invoked
+ * for every client that requests notifications/indications by writing
+ * to the "Client Configuration" descriptor for the given characteristic.
+ *
+ * @param device the remote device to receive the notification/indication
+ * @param characteristic the local characteristic that has been updated
+ * @param confirm {@code true} to request confirmation from the client (indication) or
+ * {@code false} to send a notification
+ * @param value the characteristic value
+ * @return whether the notification has been triggered successfully
+ * @throws IllegalArgumentException if the characteristic value or service is null
+ */
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @NotifyCharacteristicReturnValues
+ public int notifyCharacteristicChanged(@NonNull BluetoothDevice device,
+ @NonNull BluetoothGattCharacteristic characteristic, boolean confirm,
+ @NonNull byte[] value) {
if (VDBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress());
- if (mService == null || mServerIf == 0) return false;
+ if (mService == null || mServerIf == 0) {
+ return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+ }
+ if (characteristic == null) {
+ throw new IllegalArgumentException("characteristic must not be null");
+ }
+ if (device == null) {
+ throw new IllegalArgumentException("device must not be null");
+ }
BluetoothGattService service = characteristic.getService();
- if (service == null) return false;
-
- if (characteristic.getValue() == null) {
- throw new IllegalArgumentException("Chracteristic value is empty. Use "
- + "BluetoothGattCharacteristic#setvalue to update");
+ if (service == null) {
+ throw new IllegalArgumentException("Characteristic must have a non-null service");
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("Characteristic value must not be null");
}
try {
- mService.sendNotification(mServerIf, device.getAddress(),
+ return mService.sendNotification(mServerIf, device.getAddress(),
characteristic.getInstanceId(), confirm,
- characteristic.getValue(), mAttributionSource);
+ value, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
-
- return true;
}
/**
diff --git a/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java b/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java
new file mode 100644
index 0000000..dcaf4b6
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java
@@ -0,0 +1,129 @@
+/*
+ * 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.bluetooth;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Represents the codec configuration for a Bluetooth LE Audio source device.
+ * <p>Contains the source codec type.
+ * <p>The source codec type values are the same as those supported by the
+ * device hardware.
+ *
+ * {@see BluetoothLeAudioCodecConfig}
+ */
+public final class BluetoothLeAudioCodecConfig {
+ // Add an entry for each source codec here.
+
+ /** @hide */
+ @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = {
+ SOURCE_CODEC_TYPE_LC3,
+ SOURCE_CODEC_TYPE_INVALID
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SourceCodecType {};
+
+ public static final int SOURCE_CODEC_TYPE_LC3 = 0;
+ public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
+
+ /**
+ * Represents the count of valid source codec types. Can be accessed via
+ * {@link #getMaxCodecType}.
+ */
+ private static final int SOURCE_CODEC_TYPE_MAX = 1;
+
+ private final @SourceCodecType int mCodecType;
+
+ /**
+ * Creates a new BluetoothLeAudioCodecConfig.
+ *
+ * @param codecType the source codec type
+ */
+ private BluetoothLeAudioCodecConfig(@SourceCodecType int codecType) {
+ mCodecType = codecType;
+ }
+
+ @Override
+ public String toString() {
+ return "{codecName:" + getCodecName() + "}";
+ }
+
+ /**
+ * Gets the codec type.
+ *
+ * @return the codec type
+ */
+ public @SourceCodecType int getCodecType() {
+ return mCodecType;
+ }
+
+ /**
+ * Returns the valid codec types count.
+ */
+ public static int getMaxCodecType() {
+ return SOURCE_CODEC_TYPE_MAX;
+ }
+
+ /**
+ * Gets the codec name.
+ *
+ * @return the codec name
+ */
+ public @NonNull String getCodecName() {
+ switch (mCodecType) {
+ case SOURCE_CODEC_TYPE_LC3:
+ return "LC3";
+ case SOURCE_CODEC_TYPE_INVALID:
+ return "INVALID CODEC";
+ default:
+ break;
+ }
+ return "UNKNOWN CODEC(" + mCodecType + ")";
+ }
+
+ /**
+ * Builder for {@link BluetoothLeAudioCodecConfig}.
+ * <p> By default, the codec type will be set to
+ * {@link BluetoothLeAudioCodecConfig#SOURCE_CODEC_TYPE_INVALID}
+ */
+ public static final class Builder {
+ private int mCodecType = BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID;
+
+ /**
+ * Set codec type for Bluetooth codec config.
+ *
+ * @param codecType of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecType(@SourceCodecType int codecType) {
+ mCodecType = codecType;
+ return this;
+ }
+
+ /**
+ * Build {@link BluetoothLeAudioCodecConfig}.
+ * @return new BluetoothLeAudioCodecConfig built
+ */
+ public @NonNull BluetoothLeAudioCodecConfig build() {
+ return new BluetoothLeAudioCodecConfig(mCodecType);
+ }
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothLeBroadcast.java b/core/java/android/bluetooth/BluetoothLeBroadcast.java
new file mode 100644
index 0000000..fed9f91
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeBroadcast.java
@@ -0,0 +1,287 @@
+/*
+ * 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.bluetooth;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth LE Broadcast Source profile.
+ *
+ * <p>BluetoothLeBroadcast is a proxy object for controlling the Bluetooth LE Broadcast
+ * Source Service via IPC. Use {@link BluetoothAdapter#getProfileProxy}
+ * to get the BluetoothLeBroadcast proxy object.
+ *
+ * @hide
+ */
+public final class BluetoothLeBroadcast implements BluetoothProfile {
+ private static final String TAG = "BluetoothLeBroadcast";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /**
+ * Constants used by the LE Audio Broadcast profile for the Broadcast state
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"LE_AUDIO_BROADCAST_STATE_"}, value = {
+ LE_AUDIO_BROADCAST_STATE_DISABLED,
+ LE_AUDIO_BROADCAST_STATE_ENABLING,
+ LE_AUDIO_BROADCAST_STATE_ENABLED,
+ LE_AUDIO_BROADCAST_STATE_DISABLING,
+ LE_AUDIO_BROADCAST_STATE_PLAYING,
+ LE_AUDIO_BROADCAST_STATE_NOT_PLAYING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LeAudioBroadcastState {}
+
+ /**
+ * Indicates that LE Audio Broadcast mode is currently disabled
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_DISABLED = 10;
+
+ /**
+ * Indicates that LE Audio Broadcast mode is being enabled
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_ENABLING = 11;
+
+ /**
+ * Indicates that LE Audio Broadcast mode is currently enabled
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_ENABLED = 12;
+ /**
+ * Indicates that LE Audio Broadcast mode is being disabled
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_DISABLING = 13;
+
+ /**
+ * Indicates that an LE Audio Broadcast mode is currently playing
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_PLAYING = 14;
+
+ /**
+ * Indicates that LE Audio Broadcast is currently not playing
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_NOT_PLAYING = 15;
+
+ /**
+ * Constants used by the LE Audio Broadcast profile for encryption key length
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"LE_AUDIO_BROADCAST_ENCRYPTION_KEY_"}, value = {
+ LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT,
+ LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LeAudioEncryptionKeyLength {}
+
+ /**
+ * Indicates that the LE Audio Broadcast encryption key size is 32 bits.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT = 16;
+
+ /**
+ * Indicates that the LE Audio Broadcast encryption key size is 128 bits.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT = 17;
+
+ /**
+ * Interface for receiving events related to broadcasts
+ */
+ public interface Callback {
+ /**
+ * Called when broadcast state has changed
+ *
+ * @param prevState broadcast state before the change
+ * @param newState broadcast state after the change
+ */
+ @LeAudioBroadcastState
+ void onBroadcastStateChange(int prevState, int newState);
+ /**
+ * Called when encryption key has been updated
+ *
+ * @param success true if the key was updated successfully, false otherwise
+ */
+ void onEncryptionKeySet(boolean success);
+ }
+
+ /**
+ * Create a BluetoothLeBroadcast proxy object for interacting with the local
+ * LE Audio Broadcast Source service.
+ *
+ * @hide
+ */
+ /*package*/ BluetoothLeBroadcast(Context context,
+ BluetoothProfile.ServiceListener listener) {
+ }
+
+ /**
+ * Not supported since LE Audio Broadcasts do not establish a connection
+ *
+ * @throws UnsupportedOperationException
+ *
+ * @hide
+ */
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ throw new UnsupportedOperationException(
+ "LE Audio Broadcasts are not connection-oriented.");
+ }
+
+ /**
+ * Not supported since LE Audio Broadcasts do not establish a connection
+ *
+ * @throws UnsupportedOperationException
+ *
+ * @hide
+ */
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ throw new UnsupportedOperationException(
+ "LE Audio Broadcasts are not connection-oriented.");
+ }
+
+ /**
+ * Not supported since LE Audio Broadcasts do not establish a connection
+ *
+ * @throws UnsupportedOperationException
+ *
+ * @hide
+ */
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ throw new UnsupportedOperationException(
+ "LE Audio Broadcasts are not connection-oriented.");
+ }
+
+ /**
+ * Enable LE Audio Broadcast mode.
+ *
+ * Generates a new broadcast ID and enables sending of encrypted or unencrypted
+ * isochronous PDUs
+ *
+ * @hide
+ */
+ public int enableBroadcastMode() {
+ if (DBG) log("enableBroadcastMode");
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED;
+ }
+
+ /**
+ * Disable LE Audio Broadcast mode.
+ *
+ * @hide
+ */
+ public int disableBroadcastMode() {
+ if (DBG) log("disableBroadcastMode");
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED;
+ }
+
+ /**
+ * Get the current LE Audio broadcast state
+ *
+ * @hide
+ */
+ @LeAudioBroadcastState
+ public int getBroadcastState() {
+ if (DBG) log("getBroadcastState");
+ return LE_AUDIO_BROADCAST_STATE_DISABLED;
+ }
+
+ /**
+ * Enable LE Audio broadcast encryption
+ *
+ * @param keyLength if useExisting is true, this specifies the length of the key that should
+ * be generated
+ * @param useExisting true, if an existing key should be used
+ * false, if a new key should be generated
+ *
+ * @hide
+ */
+ @LeAudioEncryptionKeyLength
+ public int enableEncryption(boolean useExisting, int keyLength) {
+ if (DBG) log("enableEncryption useExisting=" + useExisting + " keyLength=" + keyLength);
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED;
+ }
+
+ /**
+ * Disable LE Audio broadcast encryption
+ *
+ * @param removeExisting true, if the existing key should be removed
+ * false, otherwise
+ *
+ * @hide
+ */
+ public int disableEncryption(boolean removeExisting) {
+ if (DBG) log("disableEncryption removeExisting=" + removeExisting);
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED;
+ }
+
+ /**
+ * Enable or disable LE Audio broadcast encryption
+ *
+ * @param key use the provided key if non-null, generate a new key if null
+ * @param keyLength 0 if encryption is disabled, 4 bytes (low security),
+ * 16 bytes (high security)
+ *
+ * @hide
+ */
+ @LeAudioEncryptionKeyLength
+ public int setEncryptionKey(byte[] key, int keyLength) {
+ if (DBG) log("setEncryptionKey key=" + key + " keyLength=" + keyLength);
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED;
+ }
+
+
+ /**
+ * Get the encryption key that was set before
+ *
+ * @return encryption key as a byte array or null if no encryption key was set
+ *
+ * @hide
+ */
+ public byte[] getEncryptionKey() {
+ if (DBG) log("getEncryptionKey");
+ return null;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index c000e56..8ee38d3 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -23,7 +23,6 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Attributable;
import android.content.AttributionSource;
@@ -170,7 +169,7 @@
mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- UserHandle.CURRENT_OR_SELF)) {
+ UserHandle.CURRENT)) {
Log.e(TAG, "Could not bind to Bluetooth Pbap Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 0cf9f9f..e047e5d 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -233,12 +233,19 @@
int CSIP_SET_COORDINATOR = 25;
/**
+ * LE Audio Broadcast Source
+ *
+ * @hide
+ */
+ int LE_AUDIO_BROADCAST = 26;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- int MAX_PROFILE_ID = 25;
+ int MAX_PROFILE_ID = 26;
/**
* Default priority for devices that we try to auto-connect to and
@@ -436,6 +443,8 @@
return "OPP";
case HEARING_AID:
return "HEARING_AID";
+ case LE_AUDIO:
+ return "LE_AUDIO";
default:
return "UNKNOWN_PROFILE";
}
diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java
index a254291..ecd5e40 100644
--- a/core/java/android/bluetooth/BluetoothProfileConnector.java
+++ b/core/java/android/bluetooth/BluetoothProfileConnector.java
@@ -103,7 +103,7 @@
mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- UserHandle.CURRENT_OR_SELF)) {
+ UserHandle.CURRENT)) {
logError("Could not bind to Bluetooth Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 1655b62..db5b751 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -18,7 +18,6 @@
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.LocalSocket;
@@ -266,7 +265,7 @@
throw new IOException("bt socket acept failed");
}
- as.mPfd = new ParcelFileDescriptor(fds[0]);
+ as.mPfd = ParcelFileDescriptor.dup(fds[0]);
as.mSocket = LocalSocket.createConnectedLocalSocket(fds[0]);
as.mSocketIS = as.mSocket.getInputStream();
as.mSocketOS = as.mSocket.getOutputStream();
diff --git a/core/java/android/bluetooth/BluetoothStatusCodes.java b/core/java/android/bluetooth/BluetoothStatusCodes.java
index ca01784..9dafa07 100644
--- a/core/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/core/java/android/bluetooth/BluetoothStatusCodes.java
@@ -226,6 +226,66 @@
public static final int ERROR_DISCONNECT_REASON_BAD_PARAMETERS = 1109;
/**
+ * Indicates that setting the LE Audio Broadcast mode failed.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED = 1110;
+
+ /**
+ * Indicates that setting a new encryption key for Bluetooth LE Audio Broadcast Source failed.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED = 1111;
+
+ /**
+ * Indicates that connecting to a remote Broadcast Audio Scan Service failed.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_CONNECT_FAILED = 1112;
+
+ /**
+ * Indicates that disconnecting from a remote Broadcast Audio Scan Service failed.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_DISCONNECT_FAILED = 1113;
+
+ /**
+ * Indicates that enabling LE Audio Broadcast encryption failed
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED = 1114;
+
+ /**
+ * Indicates that disabling LE Audio Broadcast encryption failed
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED = 1115;
+
+ /**
* Indicates that an unknown error has occurred has occurred.
*/
public static final int ERROR_UNKNOWN = Integer.MAX_VALUE;
diff --git a/core/java/android/bluetooth/le/TransportBlock.java b/core/java/android/bluetooth/le/TransportBlock.java
index b388bed..18bad9c 100644
--- a/core/java/android/bluetooth/le/TransportBlock.java
+++ b/core/java/android/bluetooth/le/TransportBlock.java
@@ -24,6 +24,7 @@
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
+import java.util.Arrays;
/**
* Wrapper for Transport Discovery Data Transport Blocks.
@@ -59,8 +60,12 @@
mOrgId = in.readInt();
mTdsFlags = in.readInt();
mTransportDataLength = in.readInt();
- mTransportData = new byte[mTransportDataLength];
- in.readByteArray(mTransportData);
+ if (mTransportDataLength > 0) {
+ mTransportData = new byte[mTransportDataLength];
+ in.readByteArray(mTransportData);
+ } else {
+ mTransportData = null;
+ }
}
@Override
@@ -68,7 +73,9 @@
dest.writeInt(mOrgId);
dest.writeInt(mTdsFlags);
dest.writeInt(mTransportDataLength);
- dest.writeByteArray(mTransportData);
+ if (mTransportData != null) {
+ dest.writeByteArray(mTransportData);
+ }
}
/**
@@ -79,6 +86,21 @@
return 0;
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TransportBlock other = (TransportBlock) obj;
+ return Arrays.equals(toByteArray(), other.toByteArray());
+ }
+
public static final @NonNull Creator<TransportBlock> CREATOR = new Creator<TransportBlock>() {
@Override
public TransportBlock createFromParcel(Parcel in) {
diff --git a/core/java/android/bluetooth/le/TransportDiscoveryData.java b/core/java/android/bluetooth/le/TransportDiscoveryData.java
index c8e97f9..2b52f19 100644
--- a/core/java/android/bluetooth/le/TransportDiscoveryData.java
+++ b/core/java/android/bluetooth/le/TransportDiscoveryData.java
@@ -26,6 +26,7 @@
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -96,6 +97,21 @@
return 0;
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TransportDiscoveryData other = (TransportDiscoveryData) obj;
+ return Arrays.equals(toByteArray(), other.toByteArray());
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mTransportDataType);
diff --git a/core/java/android/content/AttributionSource.aidl b/core/java/android/content/AttributionSource.aidl
index 10d5c27..7554cb2 100644
--- a/core/java/android/content/AttributionSource.aidl
+++ b/core/java/android/content/AttributionSource.aidl
@@ -16,4 +16,5 @@
package android.content;
+@JavaOnlyStableParcelable
parcelable AttributionSource;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2c4ff58..84c9fa9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -409,7 +409,7 @@
/**
* Value for {@link #flags}: {@code true} if the application may use cleartext network traffic
- * (e.g., HTTP rather than HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP
+ * (e.g., HTTP rather than HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, SMTP
* without STARTTLS or TLS). If {@code false}, the app declares that it does not intend to use
* cleartext network traffic, in which case platform components (e.g., HTTP stacks,
* {@code DownloadManager}, {@code MediaPlayer}) will refuse app's requests to use cleartext
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 2b4e4a1..95f13b5 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -6,3 +6,7 @@
# Sensors framework
per-file *Sensor*,*Trigger* = file:platform/frameworks/native:/services/sensorservice/OWNERS
+
+# Buffers
+per-file HardwareBuffer* = file:/graphics/java/android/graphics/OWNERS
+per-file DataSpace* = file:/graphics/java/android/graphics/OWNERS
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index ee24084..c906a13 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -70,9 +70,17 @@
private static final String TAG = "NetworkTemplate";
/**
+ * Initial Version of the backup serializer.
+ */
+ public static final int BACKUP_VERSION_1_INIT = 1;
+ /**
+ * Version of the backup serializer that added carrier template support.
+ */
+ public static final int BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE = 2;
+ /**
* Current Version of the Backup Serializer.
*/
- private static final int BACKUP_VERSION = 1;
+ private static final int BACKUP_VERSION = BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE;
public static final int MATCH_MOBILE = 1;
public static final int MATCH_WIFI = 4;
@@ -285,6 +293,10 @@
private final int mRoaming;
private final int mDefaultNetwork;
private final int mSubType;
+ /**
+ * The subscriber Id match rule defines how the template should match networks with
+ * specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail.
+ */
private final int mSubscriberIdMatchRule;
// Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
@@ -348,7 +360,7 @@
mSubscriberIdMatchRule = subscriberIdMatchRule;
checkValidSubscriberIdMatchRule();
if (!isKnownMatchRule(matchRule)) {
- Log.e(TAG, "Unknown network template rule " + matchRule
+ throw new IllegalArgumentException("Unknown network template rule " + matchRule
+ " will not match any identity.");
}
}
@@ -842,11 +854,17 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
+ if (!isPersistable()) {
+ Log.wtf(TAG, "Trying to backup non-persistable template: " + this);
+ }
+
out.writeInt(BACKUP_VERSION);
out.writeInt(mMatchRule);
BackupUtils.writeString(out, mSubscriberId);
BackupUtils.writeString(out, mNetworkId);
+ out.writeInt(mMetered);
+ out.writeInt(mSubscriberIdMatchRule);
return baos.toByteArray();
}
@@ -854,7 +872,7 @@
public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
throws IOException, BackupUtils.BadVersionException {
int version = in.readInt();
- if (version < 1 || version > BACKUP_VERSION) {
+ if (version < BACKUP_VERSION_1_INIT || version > BACKUP_VERSION) {
throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
}
@@ -862,11 +880,27 @@
String subscriberId = BackupUtils.readString(in);
String networkId = BackupUtils.readString(in);
- if (!isKnownMatchRule(matchRule)) {
- throw new BackupUtils.BadVersionException(
- "Restored network template contains unknown match rule " + matchRule);
+ final int metered;
+ final int subscriberIdMatchRule;
+ if (version >= BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE) {
+ metered = in.readInt();
+ subscriberIdMatchRule = in.readInt();
+ } else {
+ // For backward compatibility, fill the missing filters from match rules.
+ metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD
+ || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL;
+ subscriberIdMatchRule = SUBSCRIBER_ID_MATCH_RULE_EXACT;
}
- return new NetworkTemplate(matchRule, subscriberId, networkId);
+ try {
+ return new NetworkTemplate(matchRule,
+ subscriberId, new String[] { subscriberId },
+ networkId, metered, NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
+ NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
+ } catch (IllegalArgumentException e) {
+ throw new BackupUtils.BadVersionException(
+ "Restored network template contains unknown match rule " + matchRule, e);
+ }
}
}
diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS
index f55bcd3..b989488 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -2,5 +2,6 @@
include platform/frameworks/base:/services/core/java/com/android/server/net/OWNERS
+per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS
per-file SSL*,Uri*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com
per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS
diff --git a/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java
new file mode 100644
index 0000000..b3f7345
--- /dev/null
+++ b/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.vcn;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER;
+import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER;
+import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
+import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.PersistableBundle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+// TODO: Add documents
+/** @hide */
+public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetworkPriority {
+ private static final String ALLOWED_NETWORK_PLMN_IDS_KEY = "mAllowedNetworkPlmnIds";
+ @NonNull private final Set<String> mAllowedNetworkPlmnIds;
+ private static final String ALLOWED_SPECIFIC_CARRIER_IDS_KEY = "mAllowedSpecificCarrierIds";
+ @NonNull private final Set<Integer> mAllowedSpecificCarrierIds;
+
+ private static final String ALLOW_ROAMING_KEY = "mAllowRoaming";
+ private final boolean mAllowRoaming;
+
+ private static final String REQUIRE_OPPORTUNISTIC_KEY = "mRequireOpportunistic";
+ private final boolean mRequireOpportunistic;
+
+ private VcnCellUnderlyingNetworkPriority(
+ int networkQuality,
+ boolean allowMetered,
+ Set<String> allowedNetworkPlmnIds,
+ Set<Integer> allowedSpecificCarrierIds,
+ boolean allowRoaming,
+ boolean requireOpportunistic) {
+ super(NETWORK_PRIORITY_TYPE_CELL, networkQuality, allowMetered);
+ mAllowedNetworkPlmnIds = new ArraySet<>(allowedNetworkPlmnIds);
+ mAllowedSpecificCarrierIds = new ArraySet<>(allowedSpecificCarrierIds);
+ mAllowRoaming = allowRoaming;
+ mRequireOpportunistic = requireOpportunistic;
+
+ validate();
+ }
+
+ /** @hide */
+ @Override
+ protected void validate() {
+ super.validate();
+ validatePlmnIds(mAllowedNetworkPlmnIds);
+ Objects.requireNonNull(mAllowedSpecificCarrierIds, "allowedCarrierIds is null");
+ }
+
+ private static void validatePlmnIds(Set<String> allowedNetworkPlmnIds) {
+ Objects.requireNonNull(allowedNetworkPlmnIds, "allowedNetworkPlmnIds is null");
+
+ // A valid PLMN is a concatenation of MNC and MCC, and thus consists of 5 or 6 decimal
+ // digits.
+ for (String id : allowedNetworkPlmnIds) {
+ if ((id.length() == 5 || id.length() == 6) && id.matches("[0-9]+")) {
+ continue;
+ } else {
+ throw new IllegalArgumentException("Found invalid PLMN ID: " + id);
+ }
+ }
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public static VcnCellUnderlyingNetworkPriority fromPersistableBundle(
+ @NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle is null");
+
+ final int networkQuality = in.getInt(NETWORK_QUALITY_KEY);
+ final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY);
+
+ final PersistableBundle plmnIdsBundle =
+ in.getPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY);
+ Objects.requireNonNull(plmnIdsBundle, "plmnIdsBundle is null");
+ final Set<String> allowedNetworkPlmnIds =
+ new ArraySet<String>(
+ PersistableBundleUtils.toList(plmnIdsBundle, STRING_DESERIALIZER));
+
+ final PersistableBundle specificCarrierIdsBundle =
+ in.getPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY);
+ Objects.requireNonNull(specificCarrierIdsBundle, "specificCarrierIdsBundle is null");
+ final Set<Integer> allowedSpecificCarrierIds =
+ new ArraySet<Integer>(
+ PersistableBundleUtils.toList(
+ specificCarrierIdsBundle, INTEGER_DESERIALIZER));
+
+ final boolean allowRoaming = in.getBoolean(ALLOW_ROAMING_KEY);
+ final boolean requireOpportunistic = in.getBoolean(REQUIRE_OPPORTUNISTIC_KEY);
+
+ return new VcnCellUnderlyingNetworkPriority(
+ networkQuality,
+ allowMetered,
+ allowedNetworkPlmnIds,
+ allowedSpecificCarrierIds,
+ allowRoaming,
+ requireOpportunistic);
+ }
+
+ /** @hide */
+ @Override
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = super.toPersistableBundle();
+
+ final PersistableBundle plmnIdsBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mAllowedNetworkPlmnIds), STRING_SERIALIZER);
+ result.putPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY, plmnIdsBundle);
+
+ final PersistableBundle specificCarrierIdsBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mAllowedSpecificCarrierIds), INTEGER_SERIALIZER);
+ result.putPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY, specificCarrierIdsBundle);
+
+ result.putBoolean(ALLOW_ROAMING_KEY, mAllowRoaming);
+ result.putBoolean(REQUIRE_OPPORTUNISTIC_KEY, mRequireOpportunistic);
+
+ return result;
+ }
+
+ /** Retrieve the allowed PLMN IDs, or an empty set if any PLMN ID is acceptable. */
+ @NonNull
+ public Set<String> getAllowedOperatorPlmnIds() {
+ return Collections.unmodifiableSet(mAllowedNetworkPlmnIds);
+ }
+
+ /**
+ * Retrieve the allowed specific carrier IDs, or an empty set if any specific carrier ID is
+ * acceptable.
+ */
+ @NonNull
+ public Set<Integer> getAllowedSpecificCarrierIds() {
+ return Collections.unmodifiableSet(mAllowedSpecificCarrierIds);
+ }
+
+ /** Return if roaming is allowed. */
+ public boolean allowRoaming() {
+ return mAllowRoaming;
+ }
+
+ /** Return if requiring an opportunistic network. */
+ public boolean requireOpportunistic() {
+ return mRequireOpportunistic;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ super.hashCode(),
+ mAllowedNetworkPlmnIds,
+ mAllowedSpecificCarrierIds,
+ mAllowRoaming,
+ mRequireOpportunistic);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!super.equals(other)) {
+ return false;
+ }
+
+ if (!(other instanceof VcnCellUnderlyingNetworkPriority)) {
+ return false;
+ }
+
+ final VcnCellUnderlyingNetworkPriority rhs = (VcnCellUnderlyingNetworkPriority) other;
+ return Objects.equals(mAllowedNetworkPlmnIds, rhs.mAllowedNetworkPlmnIds)
+ && Objects.equals(mAllowedSpecificCarrierIds, rhs.mAllowedSpecificCarrierIds)
+ && mAllowRoaming == rhs.mAllowRoaming
+ && mRequireOpportunistic == rhs.mRequireOpportunistic;
+ }
+
+ /** @hide */
+ @Override
+ void dumpTransportSpecificFields(IndentingPrintWriter pw) {
+ pw.println("mAllowedNetworkPlmnIds: " + mAllowedNetworkPlmnIds.toString());
+ pw.println("mAllowedSpecificCarrierIds: " + mAllowedSpecificCarrierIds.toString());
+ pw.println("mAllowRoaming: " + mAllowRoaming);
+ pw.println("mRequireOpportunistic: " + mRequireOpportunistic);
+ }
+
+ /** This class is used to incrementally build WifiNetworkPriority objects. */
+ public static final class Builder extends VcnUnderlyingNetworkPriority.Builder<Builder> {
+ @NonNull private final Set<String> mAllowedNetworkPlmnIds = new ArraySet<>();
+ @NonNull private final Set<Integer> mAllowedSpecificCarrierIds = new ArraySet<>();
+
+ private boolean mAllowRoaming = false;
+ private boolean mRequireOpportunistic = false;
+
+ /** Construct a Builder object. */
+ public Builder() {}
+
+ /**
+ * Set allowed operator PLMN IDs.
+ *
+ * <p>This is used to distinguish cases where roaming agreements may dictate a different
+ * priority from a partner's networks.
+ *
+ * @param allowedNetworkPlmnIds the allowed operator PLMN IDs in String. Defaults to an
+ * empty set, allowing ANY PLMN ID. A valid PLMN is a concatenation of MNC and MCC, and
+ * thus consists of 5 or 6 decimal digits. See {@link SubscriptionInfo#getMccString()}
+ * and {@link SubscriptionInfo#getMncString()}.
+ */
+ @NonNull
+ public Builder setAllowedOperatorPlmnIds(@NonNull Set<String> allowedNetworkPlmnIds) {
+ validatePlmnIds(allowedNetworkPlmnIds);
+
+ mAllowedNetworkPlmnIds.clear();
+ mAllowedNetworkPlmnIds.addAll(allowedNetworkPlmnIds);
+ return this;
+ }
+
+ /**
+ * Set allowed specific carrier IDs.
+ *
+ * @param allowedSpecificCarrierIds the allowed specific carrier IDs. Defaults to an empty
+ * set, allowing ANY carrier ID. See {@link TelephonyManager#getSimSpecificCarrierId()}.
+ */
+ @NonNull
+ public Builder setAllowedSpecificCarrierIds(
+ @NonNull Set<Integer> allowedSpecificCarrierIds) {
+ Objects.requireNonNull(allowedSpecificCarrierIds, "allowedCarrierIds is null");
+ mAllowedSpecificCarrierIds.clear();
+ mAllowedSpecificCarrierIds.addAll(allowedSpecificCarrierIds);
+ return this;
+ }
+
+ /**
+ * Set if roaming is allowed.
+ *
+ * @param allowRoaming the flag to indicate if roaming is allowed. Defaults to {@code
+ * false}.
+ */
+ @NonNull
+ public Builder setAllowRoaming(boolean allowRoaming) {
+ mAllowRoaming = allowRoaming;
+ return this;
+ }
+
+ /**
+ * Set if requiring an opportunistic network.
+ *
+ * @param requireOpportunistic the flag to indicate if caller requires an opportunistic
+ * network. Defaults to {@code false}.
+ */
+ @NonNull
+ public Builder setRequireOpportunistic(boolean requireOpportunistic) {
+ mRequireOpportunistic = requireOpportunistic;
+ return this;
+ }
+
+ /** Build the VcnCellUnderlyingNetworkPriority. */
+ @NonNull
+ public VcnCellUnderlyingNetworkPriority build() {
+ return new VcnCellUnderlyingNetworkPriority(
+ mNetworkQuality,
+ mAllowMetered,
+ mAllowedNetworkPlmnIds,
+ mAllowedSpecificCarrierIds,
+ mAllowRoaming,
+ mRequireOpportunistic);
+ }
+
+ /** @hide */
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 752ef3e..55d3ecd 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -16,6 +16,7 @@
package android.net.vcn;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
import static com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -41,6 +42,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
@@ -157,6 +159,36 @@
TimeUnit.MINUTES.toMillis(5),
TimeUnit.MINUTES.toMillis(15)
};
+
+ /** @hide */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static final LinkedHashSet<VcnUnderlyingNetworkPriority>
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES = new LinkedHashSet<>();
+
+ static {
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add(
+ new VcnCellUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setAllowRoaming(true /* allowRoaming */)
+ .setRequireOpportunistic(true /* requireOpportunistic */)
+ .build());
+
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add(
+ new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .build());
+
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add(
+ new VcnCellUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setAllowRoaming(true /* allowRoaming */)
+ .setRequireOpportunistic(false /* requireOpportunistic */)
+ .build());
+ }
+
private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName";
@NonNull private final String mGatewayConnectionName;
@@ -166,6 +198,12 @@
private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
@NonNull private final SortedSet<Integer> mExposedCapabilities;
+ /** @hide */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static final String UNDERLYING_NETWORK_PRIORITIES_KEY = "mUnderlyingNetworkPriorities";
+
+ @NonNull private final LinkedHashSet<VcnUnderlyingNetworkPriority> mUnderlyingNetworkPriorities;
+
private static final String MAX_MTU_KEY = "mMaxMtu";
private final int mMaxMtu;
@@ -177,6 +215,7 @@
@NonNull String gatewayConnectionName,
@NonNull IkeTunnelConnectionParams tunnelConnectionParams,
@NonNull Set<Integer> exposedCapabilities,
+ @NonNull LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities,
@NonNull long[] retryIntervalsMs,
@IntRange(from = MIN_MTU_V6) int maxMtu) {
mGatewayConnectionName = gatewayConnectionName;
@@ -185,9 +224,16 @@
mRetryIntervalsMs = retryIntervalsMs;
mMaxMtu = maxMtu;
+ mUnderlyingNetworkPriorities = new LinkedHashSet<>(underlyingNetworkPriorities);
+ if (mUnderlyingNetworkPriorities.isEmpty()) {
+ mUnderlyingNetworkPriorities.addAll(DEFAULT_UNDERLYING_NETWORK_PRIORITIES);
+ }
+
validate();
}
+ // Null check MUST be done for all new fields added to VcnGatewayConnectionConfig, to avoid
+ // crashes when parsing PersistableBundle built on old platforms.
/** @hide */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) {
@@ -198,12 +244,30 @@
final PersistableBundle exposedCapsBundle =
in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
-
mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
mTunnelConnectionParams =
TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle);
mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
+
+ final PersistableBundle networkPrioritiesBundle =
+ in.getPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY);
+
+ if (networkPrioritiesBundle == null) {
+ // UNDERLYING_NETWORK_PRIORITIES_KEY was added in Android T. Thus
+ // VcnGatewayConnectionConfig created on old platforms will not have this data and will
+ // be assigned with the default value
+ mUnderlyingNetworkPriorities =
+ new LinkedHashSet<>(DEFAULT_UNDERLYING_NETWORK_PRIORITIES);
+
+ } else {
+ mUnderlyingNetworkPriorities =
+ new LinkedHashSet<>(
+ PersistableBundleUtils.toList(
+ networkPrioritiesBundle,
+ VcnUnderlyingNetworkPriority::fromPersistableBundle));
+ }
+
mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
mMaxMtu = in.getInt(MAX_MTU_KEY);
@@ -221,6 +285,7 @@
checkValidCapability(cap);
}
+ Objects.requireNonNull(mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null");
Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null");
validateRetryInterval(mRetryIntervalsMs);
@@ -303,6 +368,18 @@
}
/**
+ * Retrieve the configured VcnUnderlyingNetworkPriority list, or a default list if it is not
+ * configured.
+ *
+ * @see Builder#setVcnUnderlyingNetworkPriorities(LinkedHashSet<VcnUnderlyingNetworkPriority>)
+ * @hide
+ */
+ @NonNull
+ public LinkedHashSet<VcnUnderlyingNetworkPriority> getVcnUnderlyingNetworkPriorities() {
+ return new LinkedHashSet<>(mUnderlyingNetworkPriorities);
+ }
+
+ /**
* Retrieves the configured retry intervals.
*
* @see Builder#setRetryIntervalsMillis(long[])
@@ -338,10 +415,15 @@
PersistableBundleUtils.fromList(
new ArrayList<>(mExposedCapabilities),
PersistableBundleUtils.INTEGER_SERIALIZER);
+ final PersistableBundle networkPrioritiesBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mUnderlyingNetworkPriorities),
+ VcnUnderlyingNetworkPriority::toPersistableBundle);
result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle);
result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
+ result.putPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY, networkPrioritiesBundle);
result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
result.putInt(MAX_MTU_KEY, mMaxMtu);
@@ -354,6 +436,7 @@
mGatewayConnectionName,
mTunnelConnectionParams,
mExposedCapabilities,
+ mUnderlyingNetworkPriorities,
Arrays.hashCode(mRetryIntervalsMs),
mMaxMtu);
}
@@ -368,6 +451,7 @@
return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
&& mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams)
&& mExposedCapabilities.equals(rhs.mExposedCapabilities)
+ && mUnderlyingNetworkPriorities.equals(rhs.mUnderlyingNetworkPriorities)
&& Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
&& mMaxMtu == rhs.mMaxMtu;
}
@@ -379,6 +463,11 @@
@NonNull private final String mGatewayConnectionName;
@NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams;
@NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
+
+ @NonNull
+ private final LinkedHashSet<VcnUnderlyingNetworkPriority> mUnderlyingNetworkPriorities =
+ new LinkedHashSet<>(DEFAULT_UNDERLYING_NETWORK_PRIORITIES);
+
@NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
private int mMaxMtu = DEFAULT_MAX_MTU;
@@ -450,6 +539,33 @@
}
/**
+ * Set the VcnUnderlyingNetworkPriority list.
+ *
+ * @param underlyingNetworkPriorities a list of unique VcnUnderlyingNetworkPriorities that
+ * are ordered from most to least preferred, or an empty list to use the default
+ * prioritization. The default network prioritization is Opportunistic cellular, Carrier
+ * WiFi and Macro cellular
+ * @return
+ */
+ /** @hide */
+ @NonNull
+ public Builder setVcnUnderlyingNetworkPriorities(
+ @NonNull LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities) {
+ Objects.requireNonNull(
+ mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null");
+
+ mUnderlyingNetworkPriorities.clear();
+
+ if (underlyingNetworkPriorities.isEmpty()) {
+ mUnderlyingNetworkPriorities.addAll(DEFAULT_UNDERLYING_NETWORK_PRIORITIES);
+ } else {
+ mUnderlyingNetworkPriorities.addAll(underlyingNetworkPriorities);
+ }
+
+ return this;
+ }
+
+ /**
* Set the retry interval between VCN establishment attempts upon successive failures.
*
* <p>The last retry interval will be repeated until safe mode is entered, or a connection
@@ -513,6 +629,7 @@
mGatewayConnectionName,
mTunnelConnectionParams,
mExposedCapabilities,
+ mUnderlyingNetworkPriorities,
mRetryIntervalsMs,
mMaxMtu);
}
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java
new file mode 100644
index 0000000..551f757
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.vcn;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.PersistableBundle;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+// TODO: Add documents
+/** @hide */
+public abstract class VcnUnderlyingNetworkPriority {
+ /** @hide */
+ protected static final int NETWORK_PRIORITY_TYPE_WIFI = 1;
+ /** @hide */
+ protected static final int NETWORK_PRIORITY_TYPE_CELL = 2;
+
+ /** Denotes that any network quality is acceptable */
+ public static final int NETWORK_QUALITY_ANY = 0;
+ /** Denotes that network quality needs to be OK */
+ public static final int NETWORK_QUALITY_OK = 100000;
+
+ private static final SparseArray<String> NETWORK_QUALITY_TO_STRING_MAP = new SparseArray<>();
+
+ static {
+ NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_ANY, "NETWORK_QUALITY_ANY");
+ NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_OK, "NETWORK_QUALITY_OK");
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({NETWORK_QUALITY_OK, NETWORK_QUALITY_ANY})
+ public @interface NetworkQuality {}
+
+ private static final String NETWORK_PRIORITY_TYPE_KEY = "mNetworkPriorityType";
+ private final int mNetworkPriorityType;
+
+ /** @hide */
+ protected static final String NETWORK_QUALITY_KEY = "mNetworkQuality";
+ private final int mNetworkQuality;
+
+ /** @hide */
+ protected static final String ALLOW_METERED_KEY = "mAllowMetered";
+ private final boolean mAllowMetered;
+
+ /** @hide */
+ protected VcnUnderlyingNetworkPriority(
+ int networkPriorityType, int networkQuality, boolean allowMetered) {
+ mNetworkPriorityType = networkPriorityType;
+ mNetworkQuality = networkQuality;
+ mAllowMetered = allowMetered;
+ }
+
+ private static void validateNetworkQuality(int networkQuality) {
+ Preconditions.checkArgument(
+ networkQuality == NETWORK_QUALITY_ANY || networkQuality == NETWORK_QUALITY_OK,
+ "Invalid networkQuality:" + networkQuality);
+ }
+
+ /** @hide */
+ protected void validate() {
+ validateNetworkQuality(mNetworkQuality);
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public static VcnUnderlyingNetworkPriority fromPersistableBundle(
+ @NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle is null");
+
+ final int networkPriorityType = in.getInt(NETWORK_PRIORITY_TYPE_KEY);
+ switch (networkPriorityType) {
+ case NETWORK_PRIORITY_TYPE_WIFI:
+ return VcnWifiUnderlyingNetworkPriority.fromPersistableBundle(in);
+ case NETWORK_PRIORITY_TYPE_CELL:
+ return VcnCellUnderlyingNetworkPriority.fromPersistableBundle(in);
+ default:
+ throw new IllegalArgumentException(
+ "Invalid networkPriorityType:" + networkPriorityType);
+ }
+ }
+
+ /** @hide */
+ @NonNull
+ PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = new PersistableBundle();
+
+ result.putInt(NETWORK_PRIORITY_TYPE_KEY, mNetworkPriorityType);
+ result.putInt(NETWORK_QUALITY_KEY, mNetworkQuality);
+ result.putBoolean(ALLOW_METERED_KEY, mAllowMetered);
+
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNetworkPriorityType, mNetworkQuality, mAllowMetered);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!(other instanceof VcnUnderlyingNetworkPriority)) {
+ return false;
+ }
+
+ final VcnUnderlyingNetworkPriority rhs = (VcnUnderlyingNetworkPriority) other;
+ return mNetworkPriorityType == rhs.mNetworkPriorityType
+ && mNetworkQuality == rhs.mNetworkQuality
+ && mAllowMetered == rhs.mAllowMetered;
+ }
+
+ /** @hide */
+ abstract void dumpTransportSpecificFields(IndentingPrintWriter pw);
+
+ /**
+ * Dumps the state of this record for logging and debugging purposes.
+ *
+ * @hide
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println(this.getClass().getSimpleName() + ":");
+ pw.increaseIndent();
+
+ pw.println(
+ "mNetworkQuality: "
+ + NETWORK_QUALITY_TO_STRING_MAP.get(
+ mNetworkQuality, "Invalid value " + mNetworkQuality));
+ pw.println("mAllowMetered: " + mAllowMetered);
+ dumpTransportSpecificFields(pw);
+
+ pw.decreaseIndent();
+ }
+
+ /** Retrieve the required network quality. */
+ @NetworkQuality
+ public int getNetworkQuality() {
+ return mNetworkQuality;
+ }
+
+ /** Return if a metered network is allowed. */
+ public boolean allowMetered() {
+ return mAllowMetered;
+ }
+
+ /**
+ * This class is used to incrementally build VcnUnderlyingNetworkPriority objects.
+ *
+ * @param <T> The subclass to be built.
+ */
+ public abstract static class Builder<T extends Builder<T>> {
+ /** @hide */
+ protected int mNetworkQuality = NETWORK_QUALITY_ANY;
+ /** @hide */
+ protected boolean mAllowMetered = false;
+
+ /** @hide */
+ protected Builder() {}
+
+ /**
+ * Set the required network quality.
+ *
+ * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY
+ */
+ @NonNull
+ public T setNetworkQuality(@NetworkQuality int networkQuality) {
+ validateNetworkQuality(networkQuality);
+
+ mNetworkQuality = networkQuality;
+ return self();
+ }
+
+ /**
+ * Set if a metered network is allowed.
+ *
+ * @param allowMetered the flag to indicate if a metered network is allowed, defaults to
+ * {@code false}
+ */
+ @NonNull
+ public T setAllowMetered(boolean allowMetered) {
+ mAllowMetered = allowMetered;
+ return self();
+ }
+
+ /** @hide */
+ abstract T self();
+ }
+}
diff --git a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java
new file mode 100644
index 0000000..85eb100
--- /dev/null
+++ b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.vcn;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.util.Objects;
+
+// TODO: Add documents
+/** @hide */
+public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetworkPriority {
+ private static final String SSID_KEY = "mSsid";
+ @Nullable private final String mSsid;
+
+ private VcnWifiUnderlyingNetworkPriority(
+ int networkQuality, boolean allowMetered, String ssid) {
+ super(NETWORK_PRIORITY_TYPE_WIFI, networkQuality, allowMetered);
+ mSsid = ssid;
+
+ validate();
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public static VcnWifiUnderlyingNetworkPriority fromPersistableBundle(
+ @NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle is null");
+
+ final int networkQuality = in.getInt(NETWORK_QUALITY_KEY);
+ final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY);
+ final String ssid = in.getString(SSID_KEY);
+ return new VcnWifiUnderlyingNetworkPriority(networkQuality, allowMetered, ssid);
+ }
+
+ /** @hide */
+ @Override
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = super.toPersistableBundle();
+ result.putString(SSID_KEY, mSsid);
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), mSsid);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!super.equals(other)) {
+ return false;
+ }
+
+ if (!(other instanceof VcnWifiUnderlyingNetworkPriority)) {
+ return false;
+ }
+
+ final VcnWifiUnderlyingNetworkPriority rhs = (VcnWifiUnderlyingNetworkPriority) other;
+ return mSsid.equals(rhs.mSsid);
+ }
+
+ /** @hide */
+ @Override
+ void dumpTransportSpecificFields(IndentingPrintWriter pw) {
+ pw.println("mSsid: " + mSsid);
+ }
+
+ /** Retrieve the required SSID, or {@code null} if there is no requirement on SSID. */
+ @Nullable
+ public String getSsid() {
+ return mSsid;
+ }
+
+ /** This class is used to incrementally build VcnWifiUnderlyingNetworkPriority objects. */
+ public static class Builder extends VcnUnderlyingNetworkPriority.Builder<Builder> {
+ @Nullable private String mSsid;
+
+ /** Construct a Builder object. */
+ public Builder() {}
+
+ /**
+ * Set the required SSID.
+ *
+ * @param ssid the required SSID, or {@code null} if any SSID is acceptable.
+ */
+ @NonNull
+ public Builder setSsid(@Nullable String ssid) {
+ mSsid = ssid;
+ return this;
+ }
+
+ /** Build the VcnWifiUnderlyingNetworkPriority. */
+ @NonNull
+ public VcnWifiUnderlyingNetworkPriority build() {
+ return new VcnWifiUnderlyingNetworkPriority(mNetworkQuality, mAllowMetered, mSsid);
+ }
+
+ /** @hide */
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
index 74b814e..c8b4226e 100644
--- a/core/java/android/os/AppZygote.java
+++ b/core/java/android/os/AppZygote.java
@@ -45,6 +45,8 @@
// Last UID/GID of the range the AppZygote can setuid()/setgid() to
private final int mZygoteUidGidMax;
+ private final int mZygoteRuntimeFlags;
+
private final Object mLock = new Object();
/**
@@ -56,11 +58,13 @@
private final ApplicationInfo mAppInfo;
- public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax) {
+ public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax,
+ int runtimeFlags) {
mAppInfo = appInfo;
mZygoteUid = zygoteUid;
mZygoteUidGidMin = uidGidMin;
mZygoteUidGidMax = uidGidMax;
+ mZygoteRuntimeFlags = runtimeFlags;
}
/**
@@ -110,7 +114,7 @@
mZygoteUid,
mZygoteUid,
null, // gids
- 0, // runtimeFlags
+ mZygoteRuntimeFlags, // runtimeFlags
"app_zygote", // seInfo
abi, // abi
abi, // acceptedAbiList
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index be21fea..2ea6329 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -71,6 +71,9 @@
private static final String SYSTEM_DRIVER_NAME = "system";
private static final String SYSTEM_DRIVER_VERSION_NAME = "";
private static final long SYSTEM_DRIVER_VERSION_CODE = 0;
+ private static final String ANGLE_DRIVER_NAME = "angle";
+ private static final String ANGLE_DRIVER_VERSION_NAME = "";
+ private static final long ANGLE_DRIVER_VERSION_CODE = 0;
// System properties related to updatable graphics drivers.
private static final String PROPERTY_GFX_DRIVER_PRODUCTION = "ro.gfx.driver.0";
@@ -138,14 +141,24 @@
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
- setupAngle(context, coreSettings, pm, packageName);
+ boolean useAngle = false;
+ if (setupAngle(context, coreSettings, pm, packageName)) {
+ if (shouldUseAngle(context, coreSettings, packageName)) {
+ useAngle = true;
+ setGpuStats(ANGLE_DRIVER_NAME, ANGLE_DRIVER_VERSION_NAME, ANGLE_DRIVER_VERSION_CODE,
+ 0, packageName, getVulkanVersion(pm));
+ }
+ }
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver");
if (!chooseDriver(context, coreSettings, pm, packageName, appInfoWithMetaData)) {
- setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
- SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName,
- getVulkanVersion(pm));
+ if (!useAngle) {
+ setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME,
+ SYSTEM_DRIVER_VERSION_CODE,
+ SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0),
+ packageName, getVulkanVersion(pm));
+ }
}
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 92861fb..1e424d1 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -1,18 +1,6 @@
# Haptics
-per-file CombinedVibrationEffect.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file CombinedVibrationEffect.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file ExternalVibration.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file ExternalVibration.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file IExternalVibrationController.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file IExternalVibratorService.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file IVibratorManagerService.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file NullVibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file SystemVibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file SystemVibratorManager.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file VibrationEffect.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file VibrationEffect.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file Vibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file VibratorManager.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file *Vibration* = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file *Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNERS
# PowerManager
per-file IPowerManager.aidl = michaelwr@google.com, santoscordon@google.com
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 7bdb6b9..09eac79 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -846,6 +846,19 @@
}
/**
+ * Verify there are no bytes left to be read on the Parcel.
+ *
+ * @throws BadParcelableException If the current position hasn't reached the end of the Parcel.
+ * When used over binder, this exception should propagate to the caller.
+ */
+ public void enforceNoDataAvail() {
+ final int n = dataAvail();
+ if (n > 0) {
+ throw new BadParcelableException("Parcel data not fully consumed, unread size: " + n);
+ }
+ }
+
+ /**
* Writes the work source uid to the request headers.
*
* <p>It requires the headers to have been written/read already to replace the work source.
@@ -3646,26 +3659,58 @@
* list was {@code null}, {@code list} is cleared.
*
* @see #writeParcelableList(List, int)
+ *
+ * @deprecated Use the type-safer version {@link #readParcelableList(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
@NonNull
public final <T extends Parcelable> List<T> readParcelableList(@NonNull List<T> list,
@Nullable ClassLoader cl) {
- final int N = readInt();
- if (N == -1) {
+ return readParcelableListInternal(list, cl, /*clazz*/ null);
+ }
+
+ /**
+ * Same as {@link #readParcelableList(List, ClassLoader)} but accepts {@code clazz} parameter as
+ * the type required for each item.
+ *
+ * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
+ * is not an instance of that class or any of its children classes or there was an error
+ * trying to instantiate an element.
+ */
+ @NonNull
+ public <T> List<T> readParcelableList(@NonNull List<T> list,
+ @Nullable ClassLoader cl, @NonNull Class<T> clazz) {
+ Objects.requireNonNull(list);
+ Objects.requireNonNull(clazz);
+ return readParcelableListInternal(list, cl, clazz);
+ }
+
+ /**
+ * @param clazz The type of the object expected or {@code null} for performing no checks.
+ */
+ @NonNull
+ private <T> List<T> readParcelableListInternal(@NonNull List<T> list,
+ @Nullable ClassLoader cl, @Nullable Class<T> clazz) {
+ final int n = readInt();
+ if (n == -1) {
list.clear();
return list;
}
- final int M = list.size();
+ final int m = list.size();
int i = 0;
- for (; i < M && i < N; i++) {
- list.set(i, (T) readParcelable(cl));
+ for (; i < m && i < n; i++) {
+ list.set(i, (T) readParcelableInternal(cl, clazz));
}
- for (; i<N; i++) {
- list.add((T) readParcelable(cl));
+ for (; i < n; i++) {
+ list.add((T) readParcelableInternal(cl, clazz));
}
- for (; i<M; i++) {
- list.remove(N);
+ for (; i < m; i++) {
+ list.remove(n);
}
return list;
}
@@ -4165,8 +4210,7 @@
* trying to instantiate an element.
*/
@Nullable
- public <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader,
- @NonNull Class<T> clazz) {
+ public <T> T readParcelable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
Objects.requireNonNull(clazz);
return readParcelableInternal(loader, clazz);
}
@@ -4177,10 +4221,6 @@
@SuppressWarnings("unchecked")
@Nullable
private <T> T readParcelableInternal(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
- if (clazz != null && !Parcelable.class.isAssignableFrom(clazz)) {
- throw new BadParcelableException("About to unparcel a parcelable object "
- + " but class required " + clazz.getName() + " is not Parcelable");
- }
Parcelable.Creator<?> creator = readParcelableCreatorInternal(loader, clazz);
if (creator == null) {
return null;
@@ -4343,9 +4383,16 @@
* The given class loader will be used to load any enclosed
* Parcelables.
* @return the Parcelable array, or null if the array is null
+ *
+ * @deprecated Use the type-safer version {@link #readParcelableArray(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 final Parcelable[] readParcelableArray(@Nullable ClassLoader loader) {
+ public Parcelable[] readParcelableArray(@Nullable ClassLoader loader) {
int N = readInt();
if (N < 0) {
return null;
@@ -4385,6 +4432,9 @@
* @return the Serializable object, or null if the Serializable name
* wasn't found in the parcel.
*
+ * Unlike {@link #readSerializable(ClassLoader, Class)}, it uses the nearest valid class loader
+ * up the execution stack to instantiate the Serializable object.
+ *
* @deprecated Use the type-safer version {@link #readSerializable(ClassLoader, Class)} starting
* from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
@@ -4395,19 +4445,21 @@
}
/**
- * Same as {@link #readSerializable()} but accepts {@code loader} parameter
- * as the primary classLoader for resolving the Serializable class; and {@code clazz} parameter
- * as the required type.
+ * Same as {@link #readSerializable()} but accepts {@code loader} and {@code clazz} parameters.
+ *
+ * @param loader A ClassLoader from which to instantiate the Serializable object,
+ * or null for the default class loader.
+ * @param clazz The type of the object expected.
*
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children class or there there was an error
* deserializing the object.
*/
@Nullable
- public <T extends Serializable> T readSerializable(@Nullable ClassLoader loader,
- @NonNull Class<T> clazz) {
+ public <T> T readSerializable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
Objects.requireNonNull(clazz);
- return readSerializableInternal(loader, clazz);
+ return readSerializableInternal(
+ loader == null ? getClass().getClassLoader() : loader, clazz);
}
/**
@@ -4416,11 +4468,6 @@
@Nullable
private <T> T readSerializableInternal(@Nullable final ClassLoader loader,
@Nullable Class<T> clazz) {
- if (clazz != null && !Serializable.class.isAssignableFrom(clazz)) {
- throw new BadParcelableException("About to unparcel a serializable object "
- + " but class required " + clazz.getName() + " is not Serializable");
- }
-
String name = readString();
if (name == null) {
// For some reason we were unable to read the name of the Serializable (either there
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 3e01c53..b7e3068 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -238,7 +238,7 @@
public static final int DISABLED = 9;
}
- private IUpdateEngine mUpdateEngine;
+ private final IUpdateEngine mUpdateEngine;
private IUpdateEngineCallback mUpdateEngineCallback = null;
private final Object mUpdateEngineCallbackLock = new Object();
@@ -248,6 +248,9 @@
public UpdateEngine() {
mUpdateEngine = IUpdateEngine.Stub.asInterface(
ServiceManager.getService(UPDATE_ENGINE_SERVICE));
+ if (mUpdateEngine == null) {
+ throw new IllegalStateException("Failed to find update_engine");
+ }
}
/**
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index f57d157..39a2e13 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -56,11 +56,12 @@
* <ul>
* <li>{@link #MOUNT_FLAG_PRIMARY} means the volume provides primary external
* storage, historically found at {@code /sdcard}.
- * <li>{@link #MOUNT_FLAG_VISIBLE} means the volume is visible to third-party
- * apps for direct filesystem access. The system should send out relevant
- * storage broadcasts and index any media on visible volumes. Visible volumes
- * are considered a more stable part of the device, which is why we take the
- * time to index them. In particular, transient volumes like USB OTG devices
+ * <li>{@link #MOUNT_FLAG_VISIBLE_FOR_READ} and
+ * {@link #MOUNT_FLAG_VISIBLE_FOR_WRITE} mean the volume is visible to
+ * third-party apps for direct filesystem access. The system should send out
+ * relevant storage broadcasts and index any media on visible volumes. Visible
+ * volumes are considered a more stable part of the device, which is why we take
+ * the time to index them. In particular, transient volumes like USB OTG devices
* <em>should not</em> be marked as visible; their contents should be surfaced
* to apps through the Storage Access Framework.
* </ul>
@@ -100,7 +101,8 @@
public static final int STATE_BAD_REMOVAL = IVold.VOLUME_STATE_BAD_REMOVAL;
public static final int MOUNT_FLAG_PRIMARY = IVold.MOUNT_FLAG_PRIMARY;
- public static final int MOUNT_FLAG_VISIBLE = IVold.MOUNT_FLAG_VISIBLE;
+ public static final int MOUNT_FLAG_VISIBLE_FOR_READ = IVold.MOUNT_FLAG_VISIBLE_FOR_READ;
+ public static final int MOUNT_FLAG_VISIBLE_FOR_WRITE = IVold.MOUNT_FLAG_VISIBLE_FOR_WRITE;
private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
@@ -312,17 +314,31 @@
return isPrimary() && (getType() == TYPE_PUBLIC);
}
- @UnsupportedAppUsage
- public boolean isVisible() {
- return (mountFlags & MOUNT_FLAG_VISIBLE) != 0;
+ private boolean isVisibleForRead() {
+ return (mountFlags & MOUNT_FLAG_VISIBLE_FOR_READ) != 0;
}
- public boolean isVisibleForUser(int userId) {
- if ((type == TYPE_PUBLIC || type == TYPE_STUB || type == TYPE_EMULATED)
- && mountUserId == userId) {
- return isVisible();
+ private boolean isVisibleForWrite() {
+ return (mountFlags & MOUNT_FLAG_VISIBLE_FOR_WRITE) != 0;
+ }
+
+ @UnsupportedAppUsage
+ public boolean isVisible() {
+ return isVisibleForRead() || isVisibleForWrite();
+ }
+
+ private boolean isVolumeSupportedForUser(int userId) {
+ if (mountUserId != userId) {
+ return false;
}
- return false;
+ return type == TYPE_PUBLIC || type == TYPE_STUB || type == TYPE_EMULATED;
+ }
+
+ /**
+ * Returns {@code true} if this volume is visible for {@code userId}, {@code false} otherwise.
+ */
+ public boolean isVisibleForUser(int userId) {
+ return isVolumeSupportedForUser(userId) && isVisible();
}
/**
@@ -335,12 +351,12 @@
}
public boolean isVisibleForRead(int userId) {
- return isVisibleForUser(userId);
+ return isVolumeSupportedForUser(userId) && isVisibleForRead();
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isVisibleForWrite(int userId) {
- return isVisibleForUser(userId);
+ return isVolumeSupportedForUser(userId) && isVisibleForWrite();
}
@UnsupportedAppUsage
diff --git a/core/java/android/os/vibrator/OWNERS b/core/java/android/os/vibrator/OWNERS
new file mode 100644
index 0000000..b54d6bf
--- /dev/null
+++ b/core/java/android/os/vibrator/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
\ No newline at end of file
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ac520e8..84be746 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11218,22 +11218,38 @@
"night_display_forced_auto_mode_available";
/**
- * If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment
- * to SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
- * exceeded.
- * @hide
- */
+ * If UTC time between two NITZ signals is greater than this value then the second signal
+ * cannot be ignored.
+ *
+ * <p>This value is in milliseconds. It is used for telephony-based time and time zone
+ * detection.
+ * @hide
+ */
@Readable
public static final String NITZ_UPDATE_DIFF = "nitz_update_diff";
/**
- * The length of time in milli-seconds that automatic small adjustments to
- * SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
- * @hide
- */
+ * If the elapsed realtime between two NITZ signals is greater than this value then the
+ * second signal cannot be ignored.
+ *
+ * <p>This value is in milliseconds. It is used for telephony-based time and time zone
+ * detection.
+ * @hide
+ */
@Readable
public static final String NITZ_UPDATE_SPACING = "nitz_update_spacing";
+ /**
+ * If the device connects to a telephony network and was disconnected from a telephony
+ * network for less than this time, a previously received NITZ signal can be restored.
+ *
+ * <p>This value is in milliseconds. It is used for telephony-based time and time zone
+ * detection.
+ * @hide
+ */
+ public static final String NITZ_NETWORK_DISCONNECT_RETENTION =
+ "nitz_network_disconnect_retention";
+
/** Preferred NTP server. {@hide} */
@Readable
public static final String NTP_SERVER = "ntp_server";
diff --git a/core/java/android/util/BackupUtils.java b/core/java/android/util/BackupUtils.java
index 474ceda..4fcb13c 100644
--- a/core/java/android/util/BackupUtils.java
+++ b/core/java/android/util/BackupUtils.java
@@ -37,6 +37,10 @@
public BadVersionException(String message) {
super(message);
}
+
+ public BadVersionException(String message, Throwable throwable) {
+ super(message, throwable);
+ }
}
public static String readString(DataInputStream in) throws IOException {
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 8c4dcb3..cd077e1 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -22,6 +22,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayDeque;
@@ -63,7 +64,8 @@
if (mUseLocalTimestamps) {
logLine = LocalDateTime.now() + " - " + msg;
} else {
- logLine = SystemClock.elapsedRealtime() + " / " + Instant.now() + " - " + msg;
+ logLine = Duration.ofMillis(SystemClock.elapsedRealtime())
+ + " / " + Instant.now() + " - " + msg;
}
append(logLine);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3550a31..2257f6c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8448,13 +8448,13 @@
MotionEvent me = (MotionEvent) event;
if (me.getAction() == MotionEvent.ACTION_CANCEL) {
EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel",
- getTitle());
+ getTitle().toString());
}
} else if (event instanceof KeyEvent) {
KeyEvent ke = (KeyEvent) event;
if (ke.isCanceled()) {
EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel",
- getTitle());
+ getTitle().toString());
}
}
// Always enqueue the input event in order, regardless of its time stamp.
diff --git a/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java b/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java
new file mode 100644
index 0000000..615e4b79
--- /dev/null
+++ b/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.os;
+
+import android.os.Build;
+import android.util.ArrayMap;
+
+import dalvik.system.PathClassLoader;
+
+/** @hide */
+public final class SystemServerClassLoaderFactory {
+ /**
+ * Map of paths to PathClassLoader for standalone system server jars.
+ */
+ private static final ArrayMap<String, PathClassLoader> sLoadedPaths = new ArrayMap<>();
+
+ /**
+ * Creates and caches a ClassLoader for the jar at the given path, or returns a cached
+ * ClassLoader if it exists.
+ *
+ * The parent class loader should always be the system server class loader. Changing it has
+ * implications that require discussion with the mainline team.
+ *
+ * @hide for internal use only
+ */
+ public static PathClassLoader getOrCreateClassLoader(String path, ClassLoader parent) {
+ PathClassLoader pathClassLoader = sLoadedPaths.get(path);
+ if (pathClassLoader == null) {
+ pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader(
+ path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent,
+ Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null);
+ sLoadedPaths.put(path, pathClassLoader);
+ }
+ return pathClassLoader;
+ }
+}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 92d5a47..6d4b8c5 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -724,9 +724,6 @@
DataOutputStream usapOutputStream = null;
ZygoteArguments args = null;
- // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
- blockSigTerm();
-
LocalSocket sessionSocket = null;
if (argBuffer == null) {
// Read arguments from usapPoolSocket instead.
@@ -742,6 +739,10 @@
ZygoteCommandBuffer tmpArgBuffer = null;
try {
sessionSocket = usapPoolSocket.accept();
+ // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
+ // This is safe from a race condition because the pool is only flushed after
+ // the SystemServer changes its internal state to stop using the USAP pool.
+ blockSigTerm();
usapOutputStream =
new DataOutputStream(sessionSocket.getOutputStream());
@@ -759,9 +760,10 @@
unblockSigTerm();
IoUtils.closeQuietly(sessionSocket);
IoUtils.closeQuietly(tmpArgBuffer);
- blockSigTerm();
}
} else {
+ // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
+ blockSigTerm();
try {
args = ZygoteArguments.getInstance(argBuffer);
} catch (Exception ex) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 29e5a5a..6b9d95f 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -46,6 +46,7 @@
import android.system.StructCapUserData;
import android.system.StructCapUserHeader;
import android.text.Hyphenator;
+import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -560,9 +561,8 @@
/**
* Create the classloader for the system server and store it in
- * {@link sCachedSystemServerClassLoader}. This function may be called through JNI in
- * system server startup, when the runtime is in a critically low state. Do not do
- * extended computation etc here.
+ * {@link sCachedSystemServerClassLoader}. This function is called through JNI in the forked
+ * system server process in the zygote SELinux domain.
*/
private static ClassLoader getOrCreateSystemServerClassLoader() {
if (sCachedSystemServerClassLoader == null) {
@@ -576,6 +576,29 @@
}
/**
+ * Creates class loaders for standalone system server jars. This function is called through JNI
+ * in the forked system server process in the zygote SELinux domain.
+ */
+ private static void prefetchStandaloneSystemServerJars() {
+ String envStr = Os.getenv("STANDALONE_SYSTEMSERVER_JARS");
+ if (TextUtils.isEmpty(envStr)) {
+ return;
+ }
+ for (String jar : envStr.split(":")) {
+ try {
+ SystemServerClassLoaderFactory.getOrCreateClassLoader(
+ jar, getOrCreateSystemServerClassLoader());
+ } catch (Error e) {
+ // We don't want the process to crash for this error because prefetching is just an
+ // optimization.
+ Log.e(TAG,
+ String.format("Failed to prefetch standalone system server jar \"%s\": %s",
+ jar, e.toString()));
+ }
+ }
+ }
+
+ /**
* Note that preparing the profiles for system server does not require special selinux
* permissions. From the installer perspective the system server is a regular package which can
* capture profile information.
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index b0cf5dc..ae9d716 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -56,6 +56,7 @@
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -95,6 +96,9 @@
// property for runtime configuration differentiation in vendor
private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
+ private static final ArrayMap<String, ArraySet<String>> EMPTY_PERMISSIONS =
+ new ArrayMap<>();
+
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
int[] mGlobalGids = EmptyArray.INT;
@@ -224,6 +228,11 @@
final ArrayMap<String, ArraySet<String>> mSystemExtPrivAppPermissions = new ArrayMap<>();
final ArrayMap<String, ArraySet<String>> mSystemExtPrivAppDenyPermissions = new ArrayMap<>();
+ final ArrayMap<String, ArrayMap<String, ArraySet<String>>> mApexPrivAppPermissions =
+ new ArrayMap<>();
+ final ArrayMap<String, ArrayMap<String, ArraySet<String>>> mApexPrivAppDenyPermissions =
+ new ArrayMap<>();
+
final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
// Allowed associations between applications. If there are any entries
@@ -360,6 +369,18 @@
return mPrivAppDenyPermissions.get(packageName);
}
+ /** Get privapp permission allowlist for an apk-in-apex. */
+ public ArraySet<String> getApexPrivAppPermissions(String module, String packageName) {
+ return mApexPrivAppPermissions.getOrDefault(module, EMPTY_PERMISSIONS)
+ .get(packageName);
+ }
+
+ /** Get privapp permissions denylist for an apk-in-apex. */
+ public ArraySet<String> getApexPrivAppDenyPermissions(String module, String packageName) {
+ return mApexPrivAppDenyPermissions.getOrDefault(module, EMPTY_PERMISSIONS)
+ .get(packageName);
+ }
+
public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
return mVendorPrivAppPermissions.get(packageName);
}
@@ -573,8 +594,8 @@
if (!isSystemProcess()) {
return;
}
- // Read configuration of features and libs from apex module.
- int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES;
+ // Read configuration of features, libs and priv-app permissions from apex module.
+ int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
// TODO: Use a solid way to filter apex module folders?
for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
if (f.isFile() || f.getPath().contains("@")) {
@@ -1040,10 +1061,10 @@
} break;
case "privapp-permissions": {
if (allowPrivappPermissions) {
- // privapp permissions from system, vendor, product and system_ext
- // partitions are stored separately. This is to prevent xml files in
- // the vendor partition from granting permissions to priv apps in the
- // system partition and vice versa.
+ // privapp permissions from system, apex, vendor, product and
+ // system_ext partitions are stored separately. This is to
+ // prevent xml files in the vendor partition from granting
+ // permissions to priv apps in the system partition and vice versa.
boolean vendor = permFile.toPath().startsWith(
Environment.getVendorDirectory().toPath() + "/")
|| permFile.toPath().startsWith(
@@ -1052,6 +1073,8 @@
Environment.getProductDirectory().toPath() + "/");
boolean systemExt = permFile.toPath().startsWith(
Environment.getSystemExtDirectory().toPath() + "/");
+ boolean apex = permFile.toPath().startsWith(
+ Environment.getApexDirectory().toPath() + "/");
if (vendor) {
readPrivAppPermissions(parser, mVendorPrivAppPermissions,
mVendorPrivAppDenyPermissions);
@@ -1061,6 +1084,8 @@
} else if (systemExt) {
readPrivAppPermissions(parser, mSystemExtPrivAppPermissions,
mSystemExtPrivAppDenyPermissions);
+ } else if (apex) {
+ readApexPrivAppPermissions(parser, permFile);
} else {
readPrivAppPermissions(parser, mPrivAppPermissions,
mPrivAppDenyPermissions);
@@ -1616,6 +1641,43 @@
}
}
+
+ /**
+ * Returns the module name for a file in the apex module's partition.
+ */
+ private String getApexModuleNameFromFilePath(Path path) {
+ final Path apexDirectoryPath = Environment.getApexDirectory().toPath();
+ if (!path.startsWith(apexDirectoryPath)) {
+ throw new IllegalArgumentException("File " + path + " is not part of an APEX.");
+ }
+ // File must be in <apex_directory>/<module_name>/[extra_paths/]<xml_file>
+ if (path.getNameCount() <= (apexDirectoryPath.getNameCount() + 1)) {
+ throw new IllegalArgumentException("File " + path + " is in the APEX partition,"
+ + " but not inside a module.");
+ }
+ return path.getName(apexDirectoryPath.getNameCount()).toString();
+ }
+
+ private void readApexPrivAppPermissions(XmlPullParser parser, File permFile)
+ throws IOException, XmlPullParserException {
+ final String moduleName = getApexModuleNameFromFilePath(permFile.toPath());
+ final ArrayMap<String, ArraySet<String>> privAppPermissions;
+ if (mApexPrivAppPermissions.containsKey(moduleName)) {
+ privAppPermissions = mApexPrivAppPermissions.get(moduleName);
+ } else {
+ privAppPermissions = new ArrayMap<>();
+ mApexPrivAppPermissions.put(moduleName, privAppPermissions);
+ }
+ final ArrayMap<String, ArraySet<String>> privAppDenyPermissions;
+ if (mApexPrivAppDenyPermissions.containsKey(moduleName)) {
+ privAppDenyPermissions = mApexPrivAppDenyPermissions.get(moduleName);
+ } else {
+ privAppDenyPermissions = new ArrayMap<>();
+ mApexPrivAppDenyPermissions.put(moduleName, privAppDenyPermissions);
+ }
+ readPrivAppPermissions(parser, privAppPermissions, privAppDenyPermissions);
+ }
+
private static boolean isSystemProcess() {
return Process.myUid() == Process.SYSTEM_UID;
}
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 78787e5..65d073fc 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -69,6 +69,9 @@
# Although marked "view" this is mostly graphics stuff
per-file android_view_* = file:/graphics/java/android/graphics/OWNERS
+# Verity
+per-file com_android_internal_security_Verity* = ebiggers@google.com, victorhsieh@google.com
+
# VINTF
per-file android_os_VintfObject* = file:platform/system/libvintf:/OWNERS
per-file android_os_VintfRuntimeInfo* = file:platform/system/libvintf:/OWNERS
diff --git a/core/jni/android_media_AudioAttributes.cpp b/core/jni/android_media_AudioAttributes.cpp
index f1ae268..423ef7c 100644
--- a/core/jni/android_media_AudioAttributes.cpp
+++ b/core/jni/android_media_AudioAttributes.cpp
@@ -58,7 +58,7 @@
jmethodID setSystemUsage;
jmethodID setInternalCapturePreset;
jmethodID setContentType;
- jmethodID setFlags;
+ jmethodID replaceFlags;
jmethodID addTag;
} gAudioAttributesBuilderMethods;
@@ -130,7 +130,7 @@
gAudioAttributesBuilderMethods.setContentType,
attributes.content_type);
env->CallObjectMethod(jAttributeBuilder.get(),
- gAudioAttributesBuilderMethods.setFlags,
+ gAudioAttributesBuilderMethods.replaceFlags,
attributes.flags);
env->CallObjectMethod(jAttributeBuilder.get(),
gAudioAttributesBuilderMethods.addTag,
@@ -205,8 +205,8 @@
gAudioAttributesBuilderMethods.setContentType = GetMethodIDOrDie(
env, audioAttributesBuilderClass, "setContentType",
"(I)Landroid/media/AudioAttributes$Builder;");
- gAudioAttributesBuilderMethods.setFlags = GetMethodIDOrDie(
- env, audioAttributesBuilderClass, "setFlags",
+ gAudioAttributesBuilderMethods.replaceFlags = GetMethodIDOrDie(
+ env, audioAttributesBuilderClass, "replaceFlags",
"(I)Landroid/media/AudioAttributes$Builder;");
gAudioAttributesBuilderMethods.addTag = GetMethodIDOrDie(
env, audioAttributesBuilderClass, "addTag",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 4b93363..c847e4d 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2273,10 +2273,8 @@
return jStatus;
}
-static jint
-android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP(
- JNIEnv *env, jobject thiz, jobject jEncodingFormatList)
-{
+static jint android_media_AudioSystem_getHwOffloadFormatsSupportedForBluetoothMedia(
+ JNIEnv *env, jobject thiz, jint deviceType, jobject jEncodingFormatList) {
ALOGV("%s", __FUNCTION__);
jint jStatus = AUDIO_JAVA_SUCCESS;
if (!env->IsInstanceOf(jEncodingFormatList, gArrayListClass)) {
@@ -2284,8 +2282,10 @@
return (jint)AUDIO_JAVA_BAD_VALUE;
}
std::vector<audio_format_t> encodingFormats;
- status_t status = AudioSystem::getHwOffloadEncodingFormatsSupportedForA2DP(
- &encodingFormats);
+ status_t status =
+ AudioSystem::getHwOffloadFormatsSupportedForBluetoothMedia(static_cast<audio_devices_t>(
+ deviceType),
+ &encodingFormats);
if (status != NO_ERROR) {
ALOGE("%s: error %d", __FUNCTION__, status);
jStatus = nativeToJavaStatus(status);
@@ -2810,8 +2810,8 @@
{"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
{"isHapticPlaybackSupported", "()Z",
(void *)android_media_AudioSystem_isHapticPlaybackSupported},
- {"getHwOffloadEncodingFormatsSupportedForA2DP", "(Ljava/util/ArrayList;)I",
- (void *)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
+ {"getHwOffloadFormatsSupportedForBluetoothMedia", "(ILjava/util/ArrayList;)I",
+ (void *)android_media_AudioSystem_getHwOffloadFormatsSupportedForBluetoothMedia},
{"setSupportedSystemUsages", "([I)I",
(void *)android_media_AudioSystem_setSupportedSystemUsages},
{"setAllowedCapturePolicy", "(II)I",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 1b3f78c..aacf700 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -124,6 +124,7 @@
static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit";
static jclass gZygoteInitClass;
static jmethodID gGetOrCreateSystemServerClassLoader;
+static jmethodID gPrefetchStandaloneSystemServerJars;
static bool gIsSecurityEnforced = true;
@@ -1617,6 +1618,12 @@
// at a later point (but may not have rights to use AoT artifacts).
env->ExceptionClear();
}
+ // Also prefetch standalone system server jars. The reason for doing this here is the same
+ // as above.
+ env->CallStaticObjectMethod(gZygoteInitClass, gPrefetchStandaloneSystemServerJars);
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ }
}
if (setresgid(gid, gid, gid) == -1) {
@@ -2678,6 +2685,9 @@
gGetOrCreateSystemServerClassLoader =
GetStaticMethodIDOrDie(env, gZygoteInitClass, "getOrCreateSystemServerClassLoader",
"()Ljava/lang/ClassLoader;");
+ gPrefetchStandaloneSystemServerJars =
+ GetStaticMethodIDOrDie(env, gZygoteInitClass, "prefetchStandaloneSystemServerJars",
+ "()V");
RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index cc479e6..4d76aee 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1 +1,2 @@
-per-file location_time_zone_manager.proto, time_zone_detector.proto = nfuller@google.com, mingaleev@google.com
+per-file location_time_zone_manager.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
+per-file time_zone_detector.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index c3d1596..ed3968a 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -672,18 +672,31 @@
optional SettingProto new_contact_aggregator = 79 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto night_display_forced_auto_mode_available = 80 [ (android.privacy).dest = DEST_AUTOMATIC ];
- message NitzUpdate {
+ message Nitz {
option (android.msg_privacy).dest = DEST_EXPLICIT;
- // If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment to
- // SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
- // exceeded.
- optional SettingProto diff = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // The length of time in milli-seconds that automatic small adjustments to
- // SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
- optional SettingProto spacing = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // If UTC time between two NITZ signals is greater than this value then the second signal
+ // cannot be ignored.
+ //
+ // This value is in milliseconds. It is used for telephony-based time and time zone
+ // detection.
+ optional SettingProto update_diff = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ // If the elapsed realtime between two NITZ signals is greater than this value then the
+ // second signal cannot be ignored.
+ //
+ // This value is in milliseconds. It is used for telephony-based time and time zone
+ // detection.
+ optional SettingProto update_spacing = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ // If the device connects to a telephony network and was disconnected from a telephony
+ // network for less than this time, a previously received NITZ signal can be restored.
+ //
+ // This value is in milliseconds. It is used for telephony-based time and time zone
+ // detection.
+ optional SettingProto network_disconnect_retention = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
- optional NitzUpdate nitz_update = 81;
+ optional Nitz nitz = 81;
message Notification {
option (android.msg_privacy).dest = DEST_EXPLICIT;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 261334b..1a38ea1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1199,6 +1199,14 @@
android:description="@string/permdesc_readPhoneState"
android:protectionLevel="dangerous" />
+ <!-- Allows read only access to phone state with a non dangerous permission,
+ including the information like cellular network type, software version. -->
+ <permission android:name="android.permission.READ_BASIC_PHONE_STATE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readBasicPhoneState"
+ android:description="@string/permdesc_readBasicPhoneState"
+ android:protectionLevel="normal" />
+
<!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
<p>Protection level: dangerous-->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d052d70..f4acfaa 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -547,7 +547,7 @@
<attr name="allowTaskReparenting" format="boolean" />
<!-- Declare that this application may use cleartext traffic, such as HTTP rather than HTTPS;
- WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or TLS.
+ WebSockets rather than WebSockets Secure; XMPP, IMAP, SMTP without STARTTLS or TLS.
Defaults to true. If set to false {@code false}, the application declares that it does not
intend to use cleartext network traffic, in which case platform components (e.g. HTTP
stacks, {@code DownloadManager}, {@code MediaPlayer}) will refuse applications's requests
@@ -1762,7 +1762,7 @@
<!-- @deprecated replaced by setting appCategory attribute to "game" -->
<attr name="isGame" />
<!-- Declare that this application may use cleartext traffic, such as HTTP rather than
- HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or
+ HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, SMTP without STARTTLS or
TLS). Defaults to true. If set to false {@code false}, the application declares that it
does not intend to use cleartext network traffic, in which case platform components
(e.g. HTTP stacks, {@code DownloadManager}, {@code MediaPlayer}) will refuse
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index be5063f..8eede56 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1350,6 +1350,12 @@
phone number and device IDs, whether a call is active, and the remote number
connected by a call.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=80]-->
+ <string name="permlab_readBasicPhoneState">read basic telephony status and identity </string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
+ <string name="permdesc_readBasicPhoneState">Allows the app to access the basic telephony
+ features of the device.</string>
+
<!-- Title of an application permission. When granted the user is giving access to a third
party app to route its calls through the system. -->
<string name="permlab_manageOwnCalls">route calls through the system</string>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
index 59b4665..bd55426 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
@@ -17,7 +17,6 @@
package android.bluetooth;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
import junit.framework.TestCase;
@@ -34,7 +33,6 @@
BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.SOURCE_CODEC_TYPE_MAX,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID,
};
private static final int[] kCodecPriorityArray = new int[] {
@@ -168,20 +166,11 @@
long codec_specific3 = selectCodecSpecific3(config_id);
long codec_specific4 = selectCodecSpecific4(config_id);
- BluetoothCodecConfig bcc = new BluetoothCodecConfig(codec_type, codec_priority,
+ BluetoothCodecConfig bcc = buildBluetoothCodecConfig(codec_type, codec_priority,
sample_rate, bits_per_sample,
channel_mode, codec_specific1,
codec_specific2, codec_specific3,
codec_specific4);
- if (sample_rate == BluetoothCodecConfig.SAMPLE_RATE_NONE) {
- assertFalse(bcc.isValid());
- } else if (bits_per_sample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
- assertFalse(bcc.isValid());
- } else if (channel_mode == BluetoothCodecConfig.CHANNEL_MODE_NONE) {
- assertFalse(bcc.isValid());
- } else {
- assertTrue(bcc.isValid());
- }
if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) {
assertTrue(bcc.isMandatoryCodec());
@@ -204,10 +193,6 @@
if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC) {
assertEquals("LDAC", bcc.getCodecName());
}
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_MAX) {
- assertEquals("UNKNOWN CODEC(" + BluetoothCodecConfig.SOURCE_CODEC_TYPE_MAX + ")",
- bcc.getCodecName());
- }
if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
assertEquals("INVALID CODEC", bcc.getCodecName());
}
@@ -227,7 +212,7 @@
@SmallTest
public void testBluetoothCodecConfig_equals() {
BluetoothCodecConfig bcc1 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -235,7 +220,7 @@
1000, 2000, 3000, 4000);
BluetoothCodecConfig bcc2_same =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -244,7 +229,7 @@
assertTrue(bcc1.equals(bcc2_same));
BluetoothCodecConfig bcc3_codec_type =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -253,7 +238,7 @@
assertFalse(bcc1.equals(bcc3_codec_type));
BluetoothCodecConfig bcc4_codec_priority =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -262,7 +247,7 @@
assertFalse(bcc1.equals(bcc4_codec_priority));
BluetoothCodecConfig bcc5_sample_rate =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_48000,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -271,7 +256,7 @@
assertFalse(bcc1.equals(bcc5_sample_rate));
BluetoothCodecConfig bcc6_bits_per_sample =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_24,
@@ -280,7 +265,7 @@
assertFalse(bcc1.equals(bcc6_bits_per_sample));
BluetoothCodecConfig bcc7_channel_mode =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -289,7 +274,7 @@
assertFalse(bcc1.equals(bcc7_channel_mode));
BluetoothCodecConfig bcc8_codec_specific1 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -298,7 +283,7 @@
assertFalse(bcc1.equals(bcc8_codec_specific1));
BluetoothCodecConfig bcc9_codec_specific2 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -307,7 +292,7 @@
assertFalse(bcc1.equals(bcc9_codec_specific2));
BluetoothCodecConfig bcc10_codec_specific3 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -316,7 +301,7 @@
assertFalse(bcc1.equals(bcc10_codec_specific3));
BluetoothCodecConfig bcc11_codec_specific4 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -324,4 +309,21 @@
1000, 2000, 3000, 4004);
assertFalse(bcc1.equals(bcc11_codec_specific4));
}
+
+ private BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType,
+ int codecPriority, int sampleRate, int bitsPerSample, int channelMode,
+ long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) {
+ return new BluetoothCodecConfig.Builder()
+ .setCodecType(sourceCodecType)
+ .setCodecPriority(codecPriority)
+ .setSampleRate(sampleRate)
+ .setBitsPerSample(bitsPerSample)
+ .setChannelMode(channelMode)
+ .setCodecSpecific1(codecSpecific1)
+ .setCodecSpecific2(codecSpecific2)
+ .setCodecSpecific3(codecSpecific3)
+ .setCodecSpecific4(codecSpecific4)
+ .build();
+
+ }
}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
index 83bf2ed..1cb2dca 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
@@ -17,13 +17,13 @@
package android.bluetooth;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import java.util.Arrays;
-import java.util.Objects;
import junit.framework.TestCase;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
/**
* Unit test cases for {@link BluetoothCodecStatus}.
* <p>
@@ -34,7 +34,7 @@
// Codec configs: A and B are same; C is different
private static final BluetoothCodecConfig config_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -42,7 +42,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig config_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -50,7 +50,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig config_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -59,7 +59,7 @@
// Local capabilities: A and B are same; C is different
private static final BluetoothCodecConfig local_capability1_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -69,7 +69,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability1_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -79,7 +79,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability1_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -89,7 +89,7 @@
private static final BluetoothCodecConfig local_capability2_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -99,7 +99,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability2_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -109,7 +109,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability2_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -118,7 +118,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability3_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -128,7 +128,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability3_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -138,7 +138,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability3_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -147,7 +147,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability4_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -157,7 +157,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability4_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -167,7 +167,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability4_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -176,7 +176,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability5_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -190,7 +190,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability5_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -204,7 +204,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability5_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -219,7 +219,7 @@
// Selectable capabilities: A and B are same; C is different
private static final BluetoothCodecConfig selectable_capability1_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -228,7 +228,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability1_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -237,7 +237,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability1_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -245,7 +245,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability2_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -254,7 +254,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability2_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -263,7 +263,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability2_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -271,7 +271,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability3_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -280,7 +280,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability3_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -289,7 +289,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability3_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -297,7 +297,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability4_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_24,
@@ -306,7 +306,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability4_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_24,
@@ -315,7 +315,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability4_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_24,
@@ -323,7 +323,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability5_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -337,7 +337,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability5_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -351,7 +351,7 @@
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability5_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -363,79 +363,87 @@
BluetoothCodecConfig.CHANNEL_MODE_STEREO,
1000, 2000, 3000, 4000);
- private static final BluetoothCodecConfig[] local_capability_A = {
- local_capability1_A,
- local_capability2_A,
- local_capability3_A,
- local_capability4_A,
- local_capability5_A,
- };
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_A =
+ new ArrayList() {{
+ add(local_capability1_A);
+ add(local_capability2_A);
+ add(local_capability3_A);
+ add(local_capability4_A);
+ add(local_capability5_A);
+ }};
- private static final BluetoothCodecConfig[] local_capability_B = {
- local_capability1_B,
- local_capability2_B,
- local_capability3_B,
- local_capability4_B,
- local_capability5_B,
- };
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_B =
+ new ArrayList() {{
+ add(local_capability1_B);
+ add(local_capability2_B);
+ add(local_capability3_B);
+ add(local_capability4_B);
+ add(local_capability5_B);
+ }};
- private static final BluetoothCodecConfig[] local_capability_B_reordered = {
- local_capability5_B,
- local_capability4_B,
- local_capability2_B,
- local_capability3_B,
- local_capability1_B,
- };
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_B_REORDERED =
+ new ArrayList() {{
+ add(local_capability5_B);
+ add(local_capability4_B);
+ add(local_capability2_B);
+ add(local_capability3_B);
+ add(local_capability1_B);
+ }};
- private static final BluetoothCodecConfig[] local_capability_C = {
- local_capability1_C,
- local_capability2_C,
- local_capability3_C,
- local_capability4_C,
- local_capability5_C,
- };
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_C =
+ new ArrayList() {{
+ add(local_capability1_C);
+ add(local_capability2_C);
+ add(local_capability3_C);
+ add(local_capability4_C);
+ add(local_capability5_C);
+ }};
- private static final BluetoothCodecConfig[] selectable_capability_A = {
- selectable_capability1_A,
- selectable_capability2_A,
- selectable_capability3_A,
- selectable_capability4_A,
- selectable_capability5_A,
- };
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_A =
+ new ArrayList() {{
+ add(selectable_capability1_A);
+ add(selectable_capability2_A);
+ add(selectable_capability3_A);
+ add(selectable_capability4_A);
+ add(selectable_capability5_A);
+ }};
- private static final BluetoothCodecConfig[] selectable_capability_B = {
- selectable_capability1_B,
- selectable_capability2_B,
- selectable_capability3_B,
- selectable_capability4_B,
- selectable_capability5_B,
- };
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_B =
+ new ArrayList() {{
+ add(selectable_capability1_B);
+ add(selectable_capability2_B);
+ add(selectable_capability3_B);
+ add(selectable_capability4_B);
+ add(selectable_capability5_B);
+ }};
- private static final BluetoothCodecConfig[] selectable_capability_B_reordered = {
- selectable_capability5_B,
- selectable_capability4_B,
- selectable_capability2_B,
- selectable_capability3_B,
- selectable_capability1_B,
- };
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_B_REORDERED =
+ new ArrayList() {{
+ add(selectable_capability5_B);
+ add(selectable_capability4_B);
+ add(selectable_capability2_B);
+ add(selectable_capability3_B);
+ add(selectable_capability1_B);
+ }};
- private static final BluetoothCodecConfig[] selectable_capability_C = {
- selectable_capability1_C,
- selectable_capability2_C,
- selectable_capability3_C,
- selectable_capability4_C,
- selectable_capability5_C,
- };
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_C =
+ new ArrayList() {{
+ add(selectable_capability1_C);
+ add(selectable_capability2_C);
+ add(selectable_capability3_C);
+ add(selectable_capability4_C);
+ add(selectable_capability5_C);
+ }};
private static final BluetoothCodecStatus bcs_A =
- new BluetoothCodecStatus(config_A, local_capability_A, selectable_capability_A);
+ new BluetoothCodecStatus(config_A, LOCAL_CAPABILITY_A, SELECTABLE_CAPABILITY_A);
private static final BluetoothCodecStatus bcs_B =
- new BluetoothCodecStatus(config_B, local_capability_B, selectable_capability_B);
+ new BluetoothCodecStatus(config_B, LOCAL_CAPABILITY_B, SELECTABLE_CAPABILITY_B);
private static final BluetoothCodecStatus bcs_B_reordered =
- new BluetoothCodecStatus(config_B, local_capability_B_reordered,
- selectable_capability_B_reordered);
+ new BluetoothCodecStatus(config_B, LOCAL_CAPABILITY_B_REORDERED,
+ SELECTABLE_CAPABILITY_B_REORDERED);
private static final BluetoothCodecStatus bcs_C =
- new BluetoothCodecStatus(config_C, local_capability_C, selectable_capability_C);
+ new BluetoothCodecStatus(config_C, LOCAL_CAPABILITY_C, SELECTABLE_CAPABILITY_C);
@SmallTest
public void testBluetoothCodecStatus_get_methods() {
@@ -444,16 +452,16 @@
assertTrue(Objects.equals(bcs_A.getCodecConfig(), config_B));
assertFalse(Objects.equals(bcs_A.getCodecConfig(), config_C));
- assertTrue(Arrays.equals(bcs_A.getCodecsLocalCapabilities(), local_capability_A));
- assertTrue(Arrays.equals(bcs_A.getCodecsLocalCapabilities(), local_capability_B));
- assertFalse(Arrays.equals(bcs_A.getCodecsLocalCapabilities(), local_capability_C));
+ assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_A));
+ assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_B));
+ assertFalse(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_C));
- assertTrue(Arrays.equals(bcs_A.getCodecsSelectableCapabilities(),
- selectable_capability_A));
- assertTrue(Arrays.equals(bcs_A.getCodecsSelectableCapabilities(),
- selectable_capability_B));
- assertFalse(Arrays.equals(bcs_A.getCodecsSelectableCapabilities(),
- selectable_capability_C));
+ assertTrue(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_A));
+ assertTrue(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_B));
+ assertFalse(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_C));
}
@SmallTest
@@ -465,4 +473,21 @@
assertFalse(bcs_A.equals(bcs_C));
assertFalse(bcs_C.equals(bcs_A));
}
+
+ private static BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType,
+ int codecPriority, int sampleRate, int bitsPerSample, int channelMode,
+ long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) {
+ return new BluetoothCodecConfig.Builder()
+ .setCodecType(sourceCodecType)
+ .setCodecPriority(codecPriority)
+ .setSampleRate(sampleRate)
+ .setBitsPerSample(bitsPerSample)
+ .setChannelMode(channelMode)
+ .setCodecSpecific1(codecSpecific1)
+ .setCodecSpecific2(codecSpecific2)
+ .setCodecSpecific3(codecSpecific3)
+ .setCodecSpecific4(codecSpecific4)
+ .build();
+
+ }
}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java
new file mode 100644
index 0000000..c3d707c
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.bluetooth;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test cases for {@link BluetoothLeAudioCodecConfig}.
+ */
+public class BluetoothLeAudioCodecConfigTest extends TestCase {
+ private int[] mCodecTypeArray = new int[] {
+ BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3,
+ BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID,
+ };
+
+ @SmallTest
+ public void testBluetoothLeAudioCodecConfig_valid_get_methods() {
+
+ for (int codecIdx = 0; codecIdx < mCodecTypeArray.length; codecIdx++) {
+ int codecType = mCodecTypeArray[codecIdx];
+
+ BluetoothLeAudioCodecConfig leAudioCodecConfig =
+ buildBluetoothLeAudioCodecConfig(codecType);
+
+ if (codecType == BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3) {
+ assertEquals("LC3", leAudioCodecConfig.getCodecName());
+ }
+ if (codecType == BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
+ assertEquals("INVALID CODEC", leAudioCodecConfig.getCodecName());
+ }
+
+ assertEquals(codecType, leAudioCodecConfig.getCodecType());
+ }
+ }
+
+ private BluetoothLeAudioCodecConfig buildBluetoothLeAudioCodecConfig(int sourceCodecType) {
+ return new BluetoothLeAudioCodecConfig.Builder()
+ .setCodecType(sourceCodecType)
+ .build();
+
+ }
+}
diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
index 6be9306..bd4d80d 100644
--- a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
@@ -169,13 +169,13 @@
assertEquals("19/1/2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + HOUR,
FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19/1/2009–22/1/2009",
+ assertEquals("19/1/2009 – 22/1/2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19/1/2009–22/4/2009",
+ assertEquals("19/1/2009 – 22/4/2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19/1/2009–9/2/2012",
+ assertEquals("19/1/2009 – 9/2/2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
@@ -251,35 +251,35 @@
assertEquals("19–22 de enero de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
- assertEquals("19–22 de ene. de 2009",
+ assertEquals("19–22 de ene de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun, 19 de ene. – jue, 22 de ene. de 2009",
+ assertEquals("lun, 19 de ene – jue, 22 de ene de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
+ assertEquals("lunes, 19 de enero – jueves, 22 de enero de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
- assertEquals("19 de enero–22 de abril de 2009",
+ assertEquals("19 de enero – 22 de abril de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19 de ene. – 22 de abr. 2009",
+ assertEquals("19 de ene – 22 de abr 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun, 19 de ene. – mié, 22 de abr. de 2009",
+ assertEquals("lun, 19 de ene – mié, 22 de abr de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19 de ene. de 2009 – 9 de feb. de 2012",
+ assertEquals("19 de ene de 2009 – 9 de feb de 2012",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("ene. de 2009 – feb. de 2012",
+ assertEquals("ene de 2009 – feb de 2012",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
- assertEquals("19 de enero de 2009–9 de febrero de 2012",
+ assertEquals("19 de enero de 2009 – 9 de febrero de 2012",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
- assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012",
+ assertEquals("lunes, 19 de enero de 2009 – jueves, 9 de febrero de 2012",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
// The same tests but for es_ES.
@@ -291,10 +291,10 @@
assertEquals("lun, 19 ene – jue, 22 ene 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
+ assertEquals("lunes, 19 de enero – jueves, 22 de enero de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
- assertEquals("19 de enero–22 de abril de 2009",
+ assertEquals("19 de enero – 22 de abril de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
assertEquals("19 ene – 22 abr 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
@@ -311,9 +311,9 @@
assertEquals("ene 2009 – feb 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
- assertEquals("19 de enero de 2009–9 de febrero de 2012",
+ assertEquals("19 de enero de 2009 – 9 de febrero de 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0));
- assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012",
+ assertEquals("lunes, 19 de enero de 2009 – jueves, 9 de febrero de 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e81adec..1c7659e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -503,6 +503,8 @@
<permission name="android.permission.UPDATE_DEVICE_STATS" />
<!-- Permission required for GTS test - PendingSystemUpdateTest -->
<permission name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE" />
+ <!-- Permission required for ATS test - CarDevicePolicyManagerTest -->
+ <permission name="android.permission.LOCK_DEVICE" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
index d1e4309..2f61a28 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
@@ -187,7 +187,10 @@
if (!actualPerm.containsAll(expectedPerm)) {
return buildDescription(tree)
.setMessage("Method " + method.name.toString() + "() annotated " + expectedPerm
- + " but too wide; only invokes methods requiring " + actualPerm)
+ + " but too wide; only invokes methods requiring " + actualPerm
+ + "\n If calling an AIDL interface, it can be annotated by adding:"
+ + "\n @JavaPassthrough(annotation=\""
+ + "@android.annotation.RequiresPermission(...)\")")
.build();
}
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
index 850c551..6fa1a69 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
@@ -89,7 +89,7 @@
// specific sensor (the one that hasn't changed), and 2) currently the only
// signal to developers is the UserNotAuthenticatedException, which doesn't
// indicate a specific sensor.
- boolean canUnlockViaBiometrics = true;
+ boolean canUnlockViaBiometrics = biometricSids.length > 0;
for (long sid : biometricSids) {
if (!keySids.contains(sid)) {
canUnlockViaBiometrics = false;
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 2c3567a..2c005fd 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -34,206 +34,209 @@
/* 30 */ {'H', 'a', 'n', 't'},
/* 31 */ {'H', 'e', 'b', 'r'},
/* 32 */ {'H', 'l', 'u', 'w'},
- /* 33 */ {'H', 'm', 'n', 'g'},
- /* 34 */ {'H', 'm', 'n', 'p'},
- /* 35 */ {'I', 't', 'a', 'l'},
- /* 36 */ {'J', 'p', 'a', 'n'},
- /* 37 */ {'K', 'a', 'l', 'i'},
- /* 38 */ {'K', 'a', 'n', 'a'},
- /* 39 */ {'K', 'h', 'a', 'r'},
- /* 40 */ {'K', 'h', 'm', 'r'},
- /* 41 */ {'K', 'i', 't', 's'},
- /* 42 */ {'K', 'n', 'd', 'a'},
- /* 43 */ {'K', 'o', 'r', 'e'},
- /* 44 */ {'L', 'a', 'n', 'a'},
- /* 45 */ {'L', 'a', 'o', 'o'},
- /* 46 */ {'L', 'a', 't', 'n'},
- /* 47 */ {'L', 'e', 'p', 'c'},
- /* 48 */ {'L', 'i', 'n', 'a'},
- /* 49 */ {'L', 'i', 's', 'u'},
- /* 50 */ {'L', 'y', 'c', 'i'},
- /* 51 */ {'L', 'y', 'd', 'i'},
- /* 52 */ {'M', 'a', 'n', 'd'},
- /* 53 */ {'M', 'a', 'n', 'i'},
- /* 54 */ {'M', 'e', 'd', 'f'},
- /* 55 */ {'M', 'e', 'r', 'c'},
- /* 56 */ {'M', 'l', 'y', 'm'},
- /* 57 */ {'M', 'o', 'n', 'g'},
- /* 58 */ {'M', 'r', 'o', 'o'},
- /* 59 */ {'M', 'y', 'm', 'r'},
- /* 60 */ {'N', 'a', 'r', 'b'},
- /* 61 */ {'N', 'k', 'o', 'o'},
- /* 62 */ {'N', 's', 'h', 'u'},
- /* 63 */ {'O', 'g', 'a', 'm'},
- /* 64 */ {'O', 'l', 'c', 'k'},
- /* 65 */ {'O', 'r', 'k', 'h'},
- /* 66 */ {'O', 'r', 'y', 'a'},
- /* 67 */ {'O', 's', 'g', 'e'},
+ /* 33 */ {'H', 'm', 'n', 'p'},
+ /* 34 */ {'I', 't', 'a', 'l'},
+ /* 35 */ {'J', 'p', 'a', 'n'},
+ /* 36 */ {'K', 'a', 'l', 'i'},
+ /* 37 */ {'K', 'a', 'n', 'a'},
+ /* 38 */ {'K', 'h', 'a', 'r'},
+ /* 39 */ {'K', 'h', 'm', 'r'},
+ /* 40 */ {'K', 'i', 't', 's'},
+ /* 41 */ {'K', 'n', 'd', 'a'},
+ /* 42 */ {'K', 'o', 'r', 'e'},
+ /* 43 */ {'L', 'a', 'n', 'a'},
+ /* 44 */ {'L', 'a', 'o', 'o'},
+ /* 45 */ {'L', 'a', 't', 'n'},
+ /* 46 */ {'L', 'e', 'p', 'c'},
+ /* 47 */ {'L', 'i', 'n', 'a'},
+ /* 48 */ {'L', 'i', 's', 'u'},
+ /* 49 */ {'L', 'y', 'c', 'i'},
+ /* 50 */ {'L', 'y', 'd', 'i'},
+ /* 51 */ {'M', 'a', 'n', 'd'},
+ /* 52 */ {'M', 'a', 'n', 'i'},
+ /* 53 */ {'M', 'e', 'd', 'f'},
+ /* 54 */ {'M', 'e', 'r', 'c'},
+ /* 55 */ {'M', 'l', 'y', 'm'},
+ /* 56 */ {'M', 'o', 'n', 'g'},
+ /* 57 */ {'M', 'r', 'o', 'o'},
+ /* 58 */ {'M', 'y', 'm', 'r'},
+ /* 59 */ {'N', 'a', 'r', 'b'},
+ /* 60 */ {'N', 'k', 'o', 'o'},
+ /* 61 */ {'N', 's', 'h', 'u'},
+ /* 62 */ {'O', 'g', 'a', 'm'},
+ /* 63 */ {'O', 'l', 'c', 'k'},
+ /* 64 */ {'O', 'r', 'k', 'h'},
+ /* 65 */ {'O', 'r', 'y', 'a'},
+ /* 66 */ {'O', 's', 'g', 'e'},
+ /* 67 */ {'O', 'u', 'g', 'r'},
/* 68 */ {'P', 'a', 'u', 'c'},
/* 69 */ {'P', 'h', 'l', 'i'},
/* 70 */ {'P', 'h', 'n', 'x'},
/* 71 */ {'P', 'l', 'r', 'd'},
/* 72 */ {'P', 'r', 't', 'i'},
- /* 73 */ {'R', 'u', 'n', 'r'},
- /* 74 */ {'S', 'a', 'm', 'r'},
- /* 75 */ {'S', 'a', 'r', 'b'},
- /* 76 */ {'S', 'a', 'u', 'r'},
- /* 77 */ {'S', 'g', 'n', 'w'},
- /* 78 */ {'S', 'i', 'n', 'h'},
- /* 79 */ {'S', 'o', 'g', 'd'},
- /* 80 */ {'S', 'o', 'r', 'a'},
- /* 81 */ {'S', 'o', 'y', 'o'},
- /* 82 */ {'S', 'y', 'r', 'c'},
- /* 83 */ {'T', 'a', 'l', 'e'},
- /* 84 */ {'T', 'a', 'l', 'u'},
- /* 85 */ {'T', 'a', 'm', 'l'},
- /* 86 */ {'T', 'a', 'n', 'g'},
- /* 87 */ {'T', 'a', 'v', 't'},
- /* 88 */ {'T', 'e', 'l', 'u'},
- /* 89 */ {'T', 'f', 'n', 'g'},
- /* 90 */ {'T', 'h', 'a', 'a'},
- /* 91 */ {'T', 'h', 'a', 'i'},
- /* 92 */ {'T', 'i', 'b', 't'},
- /* 93 */ {'U', 'g', 'a', 'r'},
- /* 94 */ {'V', 'a', 'i', 'i'},
- /* 95 */ {'W', 'c', 'h', 'o'},
- /* 96 */ {'X', 'p', 'e', 'o'},
- /* 97 */ {'X', 's', 'u', 'x'},
- /* 98 */ {'Y', 'i', 'i', 'i'},
- /* 99 */ {'~', '~', '~', 'A'},
- /* 100 */ {'~', '~', '~', 'B'},
+ /* 73 */ {'R', 'o', 'h', 'g'},
+ /* 74 */ {'R', 'u', 'n', 'r'},
+ /* 75 */ {'S', 'a', 'm', 'r'},
+ /* 76 */ {'S', 'a', 'r', 'b'},
+ /* 77 */ {'S', 'a', 'u', 'r'},
+ /* 78 */ {'S', 'g', 'n', 'w'},
+ /* 79 */ {'S', 'i', 'n', 'h'},
+ /* 80 */ {'S', 'o', 'g', 'd'},
+ /* 81 */ {'S', 'o', 'r', 'a'},
+ /* 82 */ {'S', 'o', 'y', 'o'},
+ /* 83 */ {'S', 'y', 'r', 'c'},
+ /* 84 */ {'T', 'a', 'l', 'e'},
+ /* 85 */ {'T', 'a', 'l', 'u'},
+ /* 86 */ {'T', 'a', 'm', 'l'},
+ /* 87 */ {'T', 'a', 'n', 'g'},
+ /* 88 */ {'T', 'a', 'v', 't'},
+ /* 89 */ {'T', 'e', 'l', 'u'},
+ /* 90 */ {'T', 'f', 'n', 'g'},
+ /* 91 */ {'T', 'h', 'a', 'a'},
+ /* 92 */ {'T', 'h', 'a', 'i'},
+ /* 93 */ {'T', 'i', 'b', 't'},
+ /* 94 */ {'T', 'n', 's', 'a'},
+ /* 95 */ {'T', 'o', 't', 'o'},
+ /* 96 */ {'U', 'g', 'a', 'r'},
+ /* 97 */ {'V', 'a', 'i', 'i'},
+ /* 98 */ {'W', 'c', 'h', 'o'},
+ /* 99 */ {'X', 'p', 'e', 'o'},
+ /* 100 */ {'X', 's', 'u', 'x'},
+ /* 101 */ {'Y', 'i', 'i', 'i'},
+ /* 102 */ {'~', '~', '~', 'A'},
+ /* 103 */ {'~', '~', '~', 'B'},
};
const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
- {0x61610000u, 46u}, // aa -> Latn
- {0xA0000000u, 46u}, // aai -> Latn
- {0xA8000000u, 46u}, // aak -> Latn
- {0xD0000000u, 46u}, // aau -> Latn
+ {0x61610000u, 45u}, // aa -> Latn
+ {0xA0000000u, 45u}, // aai -> Latn
+ {0xA8000000u, 45u}, // aak -> Latn
+ {0xD0000000u, 45u}, // aau -> Latn
{0x61620000u, 18u}, // ab -> Cyrl
- {0xA0200000u, 46u}, // abi -> Latn
+ {0xA0200000u, 45u}, // abi -> Latn
{0xC0200000u, 18u}, // abq -> Cyrl
- {0xC4200000u, 46u}, // abr -> Latn
- {0xCC200000u, 46u}, // abt -> Latn
- {0xE0200000u, 46u}, // aby -> Latn
- {0x8C400000u, 46u}, // acd -> Latn
- {0x90400000u, 46u}, // ace -> Latn
- {0x9C400000u, 46u}, // ach -> Latn
- {0x80600000u, 46u}, // ada -> Latn
- {0x90600000u, 46u}, // ade -> Latn
- {0xA4600000u, 46u}, // adj -> Latn
- {0xBC600000u, 92u}, // adp -> Tibt
+ {0xC4200000u, 45u}, // abr -> Latn
+ {0xCC200000u, 45u}, // abt -> Latn
+ {0xE0200000u, 45u}, // aby -> Latn
+ {0x8C400000u, 45u}, // acd -> Latn
+ {0x90400000u, 45u}, // ace -> Latn
+ {0x9C400000u, 45u}, // ach -> Latn
+ {0x80600000u, 45u}, // ada -> Latn
+ {0x90600000u, 45u}, // ade -> Latn
+ {0xA4600000u, 45u}, // adj -> Latn
+ {0xBC600000u, 93u}, // adp -> Tibt
{0xE0600000u, 18u}, // ady -> Cyrl
- {0xE4600000u, 46u}, // adz -> Latn
+ {0xE4600000u, 45u}, // adz -> Latn
{0x61650000u, 5u}, // ae -> Avst
{0x84800000u, 2u}, // aeb -> Arab
- {0xE0800000u, 46u}, // aey -> Latn
- {0x61660000u, 46u}, // af -> Latn
- {0x88C00000u, 46u}, // agc -> Latn
- {0x8CC00000u, 46u}, // agd -> Latn
- {0x98C00000u, 46u}, // agg -> Latn
- {0xB0C00000u, 46u}, // agm -> Latn
- {0xB8C00000u, 46u}, // ago -> Latn
- {0xC0C00000u, 46u}, // agq -> Latn
- {0x80E00000u, 46u}, // aha -> Latn
- {0xACE00000u, 46u}, // ahl -> Latn
+ {0xE0800000u, 45u}, // aey -> Latn
+ {0x61660000u, 45u}, // af -> Latn
+ {0x88C00000u, 45u}, // agc -> Latn
+ {0x8CC00000u, 45u}, // agd -> Latn
+ {0x98C00000u, 45u}, // agg -> Latn
+ {0xB0C00000u, 45u}, // agm -> Latn
+ {0xB8C00000u, 45u}, // ago -> Latn
+ {0xC0C00000u, 45u}, // agq -> Latn
+ {0x80E00000u, 45u}, // aha -> Latn
+ {0xACE00000u, 45u}, // ahl -> Latn
{0xB8E00000u, 1u}, // aho -> Ahom
- {0x99200000u, 46u}, // ajg -> Latn
- {0x616B0000u, 46u}, // ak -> Latn
- {0xA9400000u, 97u}, // akk -> Xsux
- {0x81600000u, 46u}, // ala -> Latn
- {0xA1600000u, 46u}, // ali -> Latn
- {0xB5600000u, 46u}, // aln -> Latn
+ {0x99200000u, 45u}, // ajg -> Latn
+ {0x616B0000u, 45u}, // ak -> Latn
+ {0xA9400000u, 100u}, // akk -> Xsux
+ {0x81600000u, 45u}, // ala -> Latn
+ {0xA1600000u, 45u}, // ali -> Latn
+ {0xB5600000u, 45u}, // aln -> Latn
{0xCD600000u, 18u}, // alt -> Cyrl
{0x616D0000u, 21u}, // am -> Ethi
- {0xB1800000u, 46u}, // amm -> Latn
- {0xB5800000u, 46u}, // amn -> Latn
- {0xB9800000u, 46u}, // amo -> Latn
- {0xBD800000u, 46u}, // amp -> Latn
- {0x616E0000u, 46u}, // an -> Latn
- {0x89A00000u, 46u}, // anc -> Latn
- {0xA9A00000u, 46u}, // ank -> Latn
- {0xB5A00000u, 46u}, // ann -> Latn
- {0xE1A00000u, 46u}, // any -> Latn
- {0xA5C00000u, 46u}, // aoj -> Latn
- {0xB1C00000u, 46u}, // aom -> Latn
- {0xE5C00000u, 46u}, // aoz -> Latn
+ {0xB1800000u, 45u}, // amm -> Latn
+ {0xB5800000u, 45u}, // amn -> Latn
+ {0xB9800000u, 45u}, // amo -> Latn
+ {0xBD800000u, 45u}, // amp -> Latn
+ {0x616E0000u, 45u}, // an -> Latn
+ {0x89A00000u, 45u}, // anc -> Latn
+ {0xA9A00000u, 45u}, // ank -> Latn
+ {0xB5A00000u, 45u}, // ann -> Latn
+ {0xE1A00000u, 45u}, // any -> Latn
+ {0xA5C00000u, 45u}, // aoj -> Latn
+ {0xB1C00000u, 45u}, // aom -> Latn
+ {0xE5C00000u, 45u}, // aoz -> Latn
{0x89E00000u, 2u}, // apc -> Arab
{0x8DE00000u, 2u}, // apd -> Arab
- {0x91E00000u, 46u}, // ape -> Latn
- {0xC5E00000u, 46u}, // apr -> Latn
- {0xC9E00000u, 46u}, // aps -> Latn
- {0xE5E00000u, 46u}, // apz -> Latn
+ {0x91E00000u, 45u}, // ape -> Latn
+ {0xC5E00000u, 45u}, // apr -> Latn
+ {0xC9E00000u, 45u}, // aps -> Latn
+ {0xE5E00000u, 45u}, // apz -> Latn
{0x61720000u, 2u}, // ar -> Arab
- {0x61725842u, 100u}, // ar-XB -> ~~~B
+ {0x61725842u, 103u}, // ar-XB -> ~~~B
{0x8A200000u, 3u}, // arc -> Armi
- {0x9E200000u, 46u}, // arh -> Latn
- {0xB6200000u, 46u}, // arn -> Latn
- {0xBA200000u, 46u}, // aro -> Latn
+ {0x9E200000u, 45u}, // arh -> Latn
+ {0xB6200000u, 45u}, // arn -> Latn
+ {0xBA200000u, 45u}, // aro -> Latn
{0xC2200000u, 2u}, // arq -> Arab
{0xCA200000u, 2u}, // ars -> Arab
{0xE2200000u, 2u}, // ary -> Arab
{0xE6200000u, 2u}, // arz -> Arab
{0x61730000u, 8u}, // as -> Beng
- {0x82400000u, 46u}, // asa -> Latn
- {0x92400000u, 77u}, // ase -> Sgnw
- {0x9A400000u, 46u}, // asg -> Latn
- {0xBA400000u, 46u}, // aso -> Latn
- {0xCE400000u, 46u}, // ast -> Latn
- {0x82600000u, 46u}, // ata -> Latn
- {0x9A600000u, 46u}, // atg -> Latn
- {0xA6600000u, 46u}, // atj -> Latn
- {0xE2800000u, 46u}, // auy -> Latn
+ {0x82400000u, 45u}, // asa -> Latn
+ {0x92400000u, 78u}, // ase -> Sgnw
+ {0x9A400000u, 45u}, // asg -> Latn
+ {0xBA400000u, 45u}, // aso -> Latn
+ {0xCE400000u, 45u}, // ast -> Latn
+ {0x82600000u, 45u}, // ata -> Latn
+ {0x9A600000u, 45u}, // atg -> Latn
+ {0xA6600000u, 45u}, // atj -> Latn
+ {0xE2800000u, 45u}, // auy -> Latn
{0x61760000u, 18u}, // av -> Cyrl
{0xAEA00000u, 2u}, // avl -> Arab
- {0xB6A00000u, 46u}, // avn -> Latn
- {0xCEA00000u, 46u}, // avt -> Latn
- {0xD2A00000u, 46u}, // avu -> Latn
+ {0xB6A00000u, 45u}, // avn -> Latn
+ {0xCEA00000u, 45u}, // avt -> Latn
+ {0xD2A00000u, 45u}, // avu -> Latn
{0x82C00000u, 19u}, // awa -> Deva
- {0x86C00000u, 46u}, // awb -> Latn
- {0xBAC00000u, 46u}, // awo -> Latn
- {0xDEC00000u, 46u}, // awx -> Latn
- {0x61790000u, 46u}, // ay -> Latn
- {0x87000000u, 46u}, // ayb -> Latn
- {0x617A0000u, 46u}, // az -> Latn
+ {0x86C00000u, 45u}, // awb -> Latn
+ {0xBAC00000u, 45u}, // awo -> Latn
+ {0xDEC00000u, 45u}, // awx -> Latn
+ {0x61790000u, 45u}, // ay -> Latn
+ {0x87000000u, 45u}, // ayb -> Latn
+ {0x617A0000u, 45u}, // az -> Latn
{0x617A4951u, 2u}, // az-IQ -> Arab
{0x617A4952u, 2u}, // az-IR -> Arab
{0x617A5255u, 18u}, // az-RU -> Cyrl
{0x62610000u, 18u}, // ba -> Cyrl
{0xAC010000u, 2u}, // bal -> Arab
- {0xB4010000u, 46u}, // ban -> Latn
+ {0xB4010000u, 45u}, // ban -> Latn
{0xBC010000u, 19u}, // bap -> Deva
- {0xC4010000u, 46u}, // bar -> Latn
- {0xC8010000u, 46u}, // bas -> Latn
- {0xD4010000u, 46u}, // bav -> Latn
+ {0xC4010000u, 45u}, // bar -> Latn
+ {0xC8010000u, 45u}, // bas -> Latn
+ {0xD4010000u, 45u}, // bav -> Latn
{0xDC010000u, 6u}, // bax -> Bamu
- {0x80210000u, 46u}, // bba -> Latn
- {0x84210000u, 46u}, // bbb -> Latn
- {0x88210000u, 46u}, // bbc -> Latn
- {0x8C210000u, 46u}, // bbd -> Latn
- {0xA4210000u, 46u}, // bbj -> Latn
- {0xBC210000u, 46u}, // bbp -> Latn
- {0xC4210000u, 46u}, // bbr -> Latn
- {0x94410000u, 46u}, // bcf -> Latn
- {0x9C410000u, 46u}, // bch -> Latn
- {0xA0410000u, 46u}, // bci -> Latn
- {0xB0410000u, 46u}, // bcm -> Latn
- {0xB4410000u, 46u}, // bcn -> Latn
- {0xB8410000u, 46u}, // bco -> Latn
+ {0x80210000u, 45u}, // bba -> Latn
+ {0x84210000u, 45u}, // bbb -> Latn
+ {0x88210000u, 45u}, // bbc -> Latn
+ {0x8C210000u, 45u}, // bbd -> Latn
+ {0xA4210000u, 45u}, // bbj -> Latn
+ {0xBC210000u, 45u}, // bbp -> Latn
+ {0xC4210000u, 45u}, // bbr -> Latn
+ {0x94410000u, 45u}, // bcf -> Latn
+ {0x9C410000u, 45u}, // bch -> Latn
+ {0xA0410000u, 45u}, // bci -> Latn
+ {0xB0410000u, 45u}, // bcm -> Latn
+ {0xB4410000u, 45u}, // bcn -> Latn
+ {0xB8410000u, 45u}, // bco -> Latn
{0xC0410000u, 21u}, // bcq -> Ethi
- {0xD0410000u, 46u}, // bcu -> Latn
- {0x8C610000u, 46u}, // bdd -> Latn
+ {0xD0410000u, 45u}, // bcu -> Latn
+ {0x8C610000u, 45u}, // bdd -> Latn
{0x62650000u, 18u}, // be -> Cyrl
- {0x94810000u, 46u}, // bef -> Latn
- {0x9C810000u, 46u}, // beh -> Latn
+ {0x94810000u, 45u}, // bef -> Latn
+ {0x9C810000u, 45u}, // beh -> Latn
{0xA4810000u, 2u}, // bej -> Arab
- {0xB0810000u, 46u}, // bem -> Latn
- {0xCC810000u, 46u}, // bet -> Latn
- {0xD8810000u, 46u}, // bew -> Latn
- {0xDC810000u, 46u}, // bex -> Latn
- {0xE4810000u, 46u}, // bez -> Latn
- {0x8CA10000u, 46u}, // bfd -> Latn
- {0xC0A10000u, 85u}, // bfq -> Taml
+ {0xB0810000u, 45u}, // bem -> Latn
+ {0xCC810000u, 45u}, // bet -> Latn
+ {0xD8810000u, 45u}, // bew -> Latn
+ {0xDC810000u, 45u}, // bex -> Latn
+ {0xE4810000u, 45u}, // bez -> Latn
+ {0x8CA10000u, 45u}, // bfd -> Latn
+ {0xC0A10000u, 86u}, // bfq -> Taml
{0xCCA10000u, 2u}, // bft -> Arab
{0xE0A10000u, 19u}, // bfy -> Deva
{0x62670000u, 18u}, // bg -> Cyrl
@@ -241,1235 +244,1239 @@
{0xB4C10000u, 2u}, // bgn -> Arab
{0xDCC10000u, 26u}, // bgx -> Grek
{0x84E10000u, 19u}, // bhb -> Deva
- {0x98E10000u, 46u}, // bhg -> Latn
+ {0x98E10000u, 45u}, // bhg -> Latn
{0xA0E10000u, 19u}, // bhi -> Deva
- {0xACE10000u, 46u}, // bhl -> Latn
+ {0xACE10000u, 45u}, // bhl -> Latn
{0xB8E10000u, 19u}, // bho -> Deva
- {0xE0E10000u, 46u}, // bhy -> Latn
- {0x62690000u, 46u}, // bi -> Latn
- {0x85010000u, 46u}, // bib -> Latn
- {0x99010000u, 46u}, // big -> Latn
- {0xA9010000u, 46u}, // bik -> Latn
- {0xB1010000u, 46u}, // bim -> Latn
- {0xB5010000u, 46u}, // bin -> Latn
- {0xB9010000u, 46u}, // bio -> Latn
- {0xC1010000u, 46u}, // biq -> Latn
- {0x9D210000u, 46u}, // bjh -> Latn
+ {0xE0E10000u, 45u}, // bhy -> Latn
+ {0x62690000u, 45u}, // bi -> Latn
+ {0x85010000u, 45u}, // bib -> Latn
+ {0x99010000u, 45u}, // big -> Latn
+ {0xA9010000u, 45u}, // bik -> Latn
+ {0xB1010000u, 45u}, // bim -> Latn
+ {0xB5010000u, 45u}, // bin -> Latn
+ {0xB9010000u, 45u}, // bio -> Latn
+ {0xC1010000u, 45u}, // biq -> Latn
+ {0x9D210000u, 45u}, // bjh -> Latn
{0xA1210000u, 21u}, // bji -> Ethi
{0xA5210000u, 19u}, // bjj -> Deva
- {0xB5210000u, 46u}, // bjn -> Latn
- {0xB9210000u, 46u}, // bjo -> Latn
- {0xC5210000u, 46u}, // bjr -> Latn
- {0xCD210000u, 46u}, // bjt -> Latn
- {0xE5210000u, 46u}, // bjz -> Latn
- {0x89410000u, 46u}, // bkc -> Latn
- {0xB1410000u, 46u}, // bkm -> Latn
- {0xC1410000u, 46u}, // bkq -> Latn
- {0xD1410000u, 46u}, // bku -> Latn
- {0xD5410000u, 46u}, // bkv -> Latn
- {0xCD610000u, 87u}, // blt -> Tavt
- {0x626D0000u, 46u}, // bm -> Latn
- {0x9D810000u, 46u}, // bmh -> Latn
- {0xA9810000u, 46u}, // bmk -> Latn
- {0xC1810000u, 46u}, // bmq -> Latn
- {0xD1810000u, 46u}, // bmu -> Latn
+ {0xB5210000u, 45u}, // bjn -> Latn
+ {0xB9210000u, 45u}, // bjo -> Latn
+ {0xC5210000u, 45u}, // bjr -> Latn
+ {0xCD210000u, 45u}, // bjt -> Latn
+ {0xE5210000u, 45u}, // bjz -> Latn
+ {0x89410000u, 45u}, // bkc -> Latn
+ {0xB1410000u, 45u}, // bkm -> Latn
+ {0xC1410000u, 45u}, // bkq -> Latn
+ {0xD1410000u, 45u}, // bku -> Latn
+ {0xD5410000u, 45u}, // bkv -> Latn
+ {0x99610000u, 45u}, // blg -> Latn
+ {0xCD610000u, 88u}, // blt -> Tavt
+ {0x626D0000u, 45u}, // bm -> Latn
+ {0x9D810000u, 45u}, // bmh -> Latn
+ {0xA9810000u, 45u}, // bmk -> Latn
+ {0xC1810000u, 45u}, // bmq -> Latn
+ {0xD1810000u, 45u}, // bmu -> Latn
{0x626E0000u, 8u}, // bn -> Beng
- {0x99A10000u, 46u}, // bng -> Latn
- {0xB1A10000u, 46u}, // bnm -> Latn
- {0xBDA10000u, 46u}, // bnp -> Latn
- {0x626F0000u, 92u}, // bo -> Tibt
- {0xA5C10000u, 46u}, // boj -> Latn
- {0xB1C10000u, 46u}, // bom -> Latn
- {0xB5C10000u, 46u}, // bon -> Latn
+ {0x99A10000u, 45u}, // bng -> Latn
+ {0xB1A10000u, 45u}, // bnm -> Latn
+ {0xBDA10000u, 45u}, // bnp -> Latn
+ {0x626F0000u, 93u}, // bo -> Tibt
+ {0xA5C10000u, 45u}, // boj -> Latn
+ {0xB1C10000u, 45u}, // bom -> Latn
+ {0xB5C10000u, 45u}, // bon -> Latn
{0xE1E10000u, 8u}, // bpy -> Beng
- {0x8A010000u, 46u}, // bqc -> Latn
+ {0x8A010000u, 45u}, // bqc -> Latn
{0xA2010000u, 2u}, // bqi -> Arab
- {0xBE010000u, 46u}, // bqp -> Latn
- {0xD6010000u, 46u}, // bqv -> Latn
- {0x62720000u, 46u}, // br -> Latn
+ {0xBE010000u, 45u}, // bqp -> Latn
+ {0xD6010000u, 45u}, // bqv -> Latn
+ {0x62720000u, 45u}, // br -> Latn
{0x82210000u, 19u}, // bra -> Deva
{0x9E210000u, 2u}, // brh -> Arab
{0xDE210000u, 19u}, // brx -> Deva
- {0xE6210000u, 46u}, // brz -> Latn
- {0x62730000u, 46u}, // bs -> Latn
- {0xA6410000u, 46u}, // bsj -> Latn
+ {0xE6210000u, 45u}, // brz -> Latn
+ {0x62730000u, 45u}, // bs -> Latn
+ {0xA6410000u, 45u}, // bsj -> Latn
{0xC2410000u, 7u}, // bsq -> Bass
- {0xCA410000u, 46u}, // bss -> Latn
+ {0xCA410000u, 45u}, // bss -> Latn
{0xCE410000u, 21u}, // bst -> Ethi
- {0xBA610000u, 46u}, // bto -> Latn
- {0xCE610000u, 46u}, // btt -> Latn
+ {0xBA610000u, 45u}, // bto -> Latn
+ {0xCE610000u, 45u}, // btt -> Latn
{0xD6610000u, 19u}, // btv -> Deva
{0x82810000u, 18u}, // bua -> Cyrl
- {0x8A810000u, 46u}, // buc -> Latn
- {0x8E810000u, 46u}, // bud -> Latn
- {0x9A810000u, 46u}, // bug -> Latn
- {0xAA810000u, 46u}, // buk -> Latn
- {0xB2810000u, 46u}, // bum -> Latn
- {0xBA810000u, 46u}, // buo -> Latn
- {0xCA810000u, 46u}, // bus -> Latn
- {0xD2810000u, 46u}, // buu -> Latn
- {0x86A10000u, 46u}, // bvb -> Latn
- {0x8EC10000u, 46u}, // bwd -> Latn
- {0xC6C10000u, 46u}, // bwr -> Latn
- {0x9EE10000u, 46u}, // bxh -> Latn
- {0x93010000u, 46u}, // bye -> Latn
+ {0x8A810000u, 45u}, // buc -> Latn
+ {0x8E810000u, 45u}, // bud -> Latn
+ {0x9A810000u, 45u}, // bug -> Latn
+ {0xAA810000u, 45u}, // buk -> Latn
+ {0xB2810000u, 45u}, // bum -> Latn
+ {0xBA810000u, 45u}, // buo -> Latn
+ {0xCA810000u, 45u}, // bus -> Latn
+ {0xD2810000u, 45u}, // buu -> Latn
+ {0x86A10000u, 45u}, // bvb -> Latn
+ {0x8EC10000u, 45u}, // bwd -> Latn
+ {0xC6C10000u, 45u}, // bwr -> Latn
+ {0x9EE10000u, 45u}, // bxh -> Latn
+ {0x93010000u, 45u}, // bye -> Latn
{0xB7010000u, 21u}, // byn -> Ethi
- {0xC7010000u, 46u}, // byr -> Latn
- {0xCB010000u, 46u}, // bys -> Latn
- {0xD7010000u, 46u}, // byv -> Latn
- {0xDF010000u, 46u}, // byx -> Latn
- {0x83210000u, 46u}, // bza -> Latn
- {0x93210000u, 46u}, // bze -> Latn
- {0x97210000u, 46u}, // bzf -> Latn
- {0x9F210000u, 46u}, // bzh -> Latn
- {0xDB210000u, 46u}, // bzw -> Latn
- {0x63610000u, 46u}, // ca -> Latn
- {0x8C020000u, 46u}, // cad -> Latn
- {0xB4020000u, 46u}, // can -> Latn
- {0xA4220000u, 46u}, // cbj -> Latn
- {0x9C420000u, 46u}, // cch -> Latn
+ {0xC7010000u, 45u}, // byr -> Latn
+ {0xCB010000u, 45u}, // bys -> Latn
+ {0xD7010000u, 45u}, // byv -> Latn
+ {0xDF010000u, 45u}, // byx -> Latn
+ {0x83210000u, 45u}, // bza -> Latn
+ {0x93210000u, 45u}, // bze -> Latn
+ {0x97210000u, 45u}, // bzf -> Latn
+ {0x9F210000u, 45u}, // bzh -> Latn
+ {0xDB210000u, 45u}, // bzw -> Latn
+ {0x63610000u, 45u}, // ca -> Latn
+ {0x8C020000u, 45u}, // cad -> Latn
+ {0xB4020000u, 45u}, // can -> Latn
+ {0xA4220000u, 45u}, // cbj -> Latn
+ {0x9C420000u, 45u}, // cch -> Latn
{0xBC420000u, 10u}, // ccp -> Cakm
{0x63650000u, 18u}, // ce -> Cyrl
- {0x84820000u, 46u}, // ceb -> Latn
- {0x80A20000u, 46u}, // cfa -> Latn
- {0x98C20000u, 46u}, // cgg -> Latn
- {0x63680000u, 46u}, // ch -> Latn
- {0xA8E20000u, 46u}, // chk -> Latn
+ {0x84820000u, 45u}, // ceb -> Latn
+ {0x80A20000u, 45u}, // cfa -> Latn
+ {0x98C20000u, 45u}, // cgg -> Latn
+ {0x63680000u, 45u}, // ch -> Latn
+ {0xA8E20000u, 45u}, // chk -> Latn
{0xB0E20000u, 18u}, // chm -> Cyrl
- {0xB8E20000u, 46u}, // cho -> Latn
- {0xBCE20000u, 46u}, // chp -> Latn
+ {0xB8E20000u, 45u}, // cho -> Latn
+ {0xBCE20000u, 45u}, // chp -> Latn
{0xC4E20000u, 14u}, // chr -> Cher
- {0x89020000u, 46u}, // cic -> Latn
+ {0x89020000u, 45u}, // cic -> Latn
{0x81220000u, 2u}, // cja -> Arab
{0xB1220000u, 13u}, // cjm -> Cham
- {0xD5220000u, 46u}, // cjv -> Latn
+ {0xD5220000u, 45u}, // cjv -> Latn
{0x85420000u, 2u}, // ckb -> Arab
- {0xAD420000u, 46u}, // ckl -> Latn
- {0xB9420000u, 46u}, // cko -> Latn
- {0xE1420000u, 46u}, // cky -> Latn
- {0x81620000u, 46u}, // cla -> Latn
- {0x91820000u, 46u}, // cme -> Latn
- {0x99820000u, 81u}, // cmg -> Soyo
- {0x636F0000u, 46u}, // co -> Latn
+ {0xAD420000u, 45u}, // ckl -> Latn
+ {0xB9420000u, 45u}, // cko -> Latn
+ {0xE1420000u, 45u}, // cky -> Latn
+ {0x81620000u, 45u}, // cla -> Latn
+ {0x91820000u, 45u}, // cme -> Latn
+ {0x99820000u, 82u}, // cmg -> Soyo
+ {0x636F0000u, 45u}, // co -> Latn
{0xBDC20000u, 16u}, // cop -> Copt
- {0xC9E20000u, 46u}, // cps -> Latn
+ {0xC9E20000u, 45u}, // cps -> Latn
{0x63720000u, 11u}, // cr -> Cans
{0x9E220000u, 18u}, // crh -> Cyrl
{0xA6220000u, 11u}, // crj -> Cans
{0xAA220000u, 11u}, // crk -> Cans
{0xAE220000u, 11u}, // crl -> Cans
{0xB2220000u, 11u}, // crm -> Cans
- {0xCA220000u, 46u}, // crs -> Latn
- {0x63730000u, 46u}, // cs -> Latn
- {0x86420000u, 46u}, // csb -> Latn
+ {0xCA220000u, 45u}, // crs -> Latn
+ {0x63730000u, 45u}, // cs -> Latn
+ {0x86420000u, 45u}, // csb -> Latn
{0xDA420000u, 11u}, // csw -> Cans
{0x8E620000u, 68u}, // ctd -> Pauc
{0x63750000u, 18u}, // cu -> Cyrl
{0x63760000u, 18u}, // cv -> Cyrl
- {0x63790000u, 46u}, // cy -> Latn
- {0x64610000u, 46u}, // da -> Latn
- {0x8C030000u, 46u}, // dad -> Latn
- {0x94030000u, 46u}, // daf -> Latn
- {0x98030000u, 46u}, // dag -> Latn
- {0x9C030000u, 46u}, // dah -> Latn
- {0xA8030000u, 46u}, // dak -> Latn
+ {0x63790000u, 45u}, // cy -> Latn
+ {0x64610000u, 45u}, // da -> Latn
+ {0x8C030000u, 45u}, // dad -> Latn
+ {0x94030000u, 45u}, // daf -> Latn
+ {0x98030000u, 45u}, // dag -> Latn
+ {0x9C030000u, 45u}, // dah -> Latn
+ {0xA8030000u, 45u}, // dak -> Latn
{0xC4030000u, 18u}, // dar -> Cyrl
- {0xD4030000u, 46u}, // dav -> Latn
- {0x8C230000u, 46u}, // dbd -> Latn
- {0xC0230000u, 46u}, // dbq -> Latn
+ {0xD4030000u, 45u}, // dav -> Latn
+ {0x8C230000u, 45u}, // dbd -> Latn
+ {0xC0230000u, 45u}, // dbq -> Latn
{0x88430000u, 2u}, // dcc -> Arab
- {0xB4630000u, 46u}, // ddn -> Latn
- {0x64650000u, 46u}, // de -> Latn
- {0x8C830000u, 46u}, // ded -> Latn
- {0xB4830000u, 46u}, // den -> Latn
- {0x80C30000u, 46u}, // dga -> Latn
- {0x9CC30000u, 46u}, // dgh -> Latn
- {0xA0C30000u, 46u}, // dgi -> Latn
+ {0xB4630000u, 45u}, // ddn -> Latn
+ {0x64650000u, 45u}, // de -> Latn
+ {0x8C830000u, 45u}, // ded -> Latn
+ {0xB4830000u, 45u}, // den -> Latn
+ {0x80C30000u, 45u}, // dga -> Latn
+ {0x9CC30000u, 45u}, // dgh -> Latn
+ {0xA0C30000u, 45u}, // dgi -> Latn
{0xACC30000u, 2u}, // dgl -> Arab
- {0xC4C30000u, 46u}, // dgr -> Latn
- {0xE4C30000u, 46u}, // dgz -> Latn
- {0x81030000u, 46u}, // dia -> Latn
- {0x91230000u, 46u}, // dje -> Latn
- {0x95830000u, 54u}, // dmf -> Medf
- {0xA5A30000u, 46u}, // dnj -> Latn
- {0x85C30000u, 46u}, // dob -> Latn
+ {0xC4C30000u, 45u}, // dgr -> Latn
+ {0xE4C30000u, 45u}, // dgz -> Latn
+ {0x81030000u, 45u}, // dia -> Latn
+ {0x91230000u, 45u}, // dje -> Latn
+ {0x95830000u, 53u}, // dmf -> Medf
+ {0xA5A30000u, 45u}, // dnj -> Latn
+ {0x85C30000u, 45u}, // dob -> Latn
{0xA1C30000u, 19u}, // doi -> Deva
- {0xBDC30000u, 46u}, // dop -> Latn
- {0xD9C30000u, 46u}, // dow -> Latn
- {0x9E230000u, 57u}, // drh -> Mong
- {0xA2230000u, 46u}, // dri -> Latn
+ {0xBDC30000u, 45u}, // dop -> Latn
+ {0xD9C30000u, 45u}, // dow -> Latn
+ {0x9E230000u, 56u}, // drh -> Mong
+ {0xA2230000u, 45u}, // dri -> Latn
{0xCA230000u, 21u}, // drs -> Ethi
- {0x86430000u, 46u}, // dsb -> Latn
- {0xB2630000u, 46u}, // dtm -> Latn
- {0xBE630000u, 46u}, // dtp -> Latn
- {0xCA630000u, 46u}, // dts -> Latn
+ {0x86430000u, 45u}, // dsb -> Latn
+ {0xB2630000u, 45u}, // dtm -> Latn
+ {0xBE630000u, 45u}, // dtp -> Latn
+ {0xCA630000u, 45u}, // dts -> Latn
{0xE2630000u, 19u}, // dty -> Deva
- {0x82830000u, 46u}, // dua -> Latn
- {0x8A830000u, 46u}, // duc -> Latn
- {0x8E830000u, 46u}, // dud -> Latn
- {0x9A830000u, 46u}, // dug -> Latn
- {0x64760000u, 90u}, // dv -> Thaa
- {0x82A30000u, 46u}, // dva -> Latn
- {0xDAC30000u, 46u}, // dww -> Latn
- {0xBB030000u, 46u}, // dyo -> Latn
- {0xD3030000u, 46u}, // dyu -> Latn
- {0x647A0000u, 92u}, // dz -> Tibt
- {0x9B230000u, 46u}, // dzg -> Latn
- {0xD0240000u, 46u}, // ebu -> Latn
- {0x65650000u, 46u}, // ee -> Latn
- {0xA0A40000u, 46u}, // efi -> Latn
- {0xACC40000u, 46u}, // egl -> Latn
+ {0x82830000u, 45u}, // dua -> Latn
+ {0x8A830000u, 45u}, // duc -> Latn
+ {0x8E830000u, 45u}, // dud -> Latn
+ {0x9A830000u, 45u}, // dug -> Latn
+ {0x64760000u, 91u}, // dv -> Thaa
+ {0x82A30000u, 45u}, // dva -> Latn
+ {0xDAC30000u, 45u}, // dww -> Latn
+ {0xBB030000u, 45u}, // dyo -> Latn
+ {0xD3030000u, 45u}, // dyu -> Latn
+ {0x647A0000u, 93u}, // dz -> Tibt
+ {0x9B230000u, 45u}, // dzg -> Latn
+ {0xD0240000u, 45u}, // ebu -> Latn
+ {0x65650000u, 45u}, // ee -> Latn
+ {0xA0A40000u, 45u}, // efi -> Latn
+ {0xACC40000u, 45u}, // egl -> Latn
{0xE0C40000u, 20u}, // egy -> Egyp
- {0x81440000u, 46u}, // eka -> Latn
- {0xE1440000u, 37u}, // eky -> Kali
+ {0x81440000u, 45u}, // eka -> Latn
+ {0xE1440000u, 36u}, // eky -> Kali
{0x656C0000u, 26u}, // el -> Grek
- {0x81840000u, 46u}, // ema -> Latn
- {0xA1840000u, 46u}, // emi -> Latn
- {0x656E0000u, 46u}, // en -> Latn
- {0x656E5841u, 99u}, // en-XA -> ~~~A
- {0xB5A40000u, 46u}, // enn -> Latn
- {0xC1A40000u, 46u}, // enq -> Latn
- {0x656F0000u, 46u}, // eo -> Latn
- {0xA2240000u, 46u}, // eri -> Latn
- {0x65730000u, 46u}, // es -> Latn
+ {0x81840000u, 45u}, // ema -> Latn
+ {0xA1840000u, 45u}, // emi -> Latn
+ {0x656E0000u, 45u}, // en -> Latn
+ {0x656E5841u, 102u}, // en-XA -> ~~~A
+ {0xB5A40000u, 45u}, // enn -> Latn
+ {0xC1A40000u, 45u}, // enq -> Latn
+ {0x656F0000u, 45u}, // eo -> Latn
+ {0xA2240000u, 45u}, // eri -> Latn
+ {0x65730000u, 45u}, // es -> Latn
{0x9A440000u, 24u}, // esg -> Gonm
- {0xD2440000u, 46u}, // esu -> Latn
- {0x65740000u, 46u}, // et -> Latn
- {0xC6640000u, 46u}, // etr -> Latn
- {0xCE640000u, 35u}, // ett -> Ital
- {0xD2640000u, 46u}, // etu -> Latn
- {0xDE640000u, 46u}, // etx -> Latn
- {0x65750000u, 46u}, // eu -> Latn
- {0xBAC40000u, 46u}, // ewo -> Latn
- {0xCEE40000u, 46u}, // ext -> Latn
- {0x83240000u, 46u}, // eza -> Latn
+ {0xD2440000u, 45u}, // esu -> Latn
+ {0x65740000u, 45u}, // et -> Latn
+ {0xC6640000u, 45u}, // etr -> Latn
+ {0xCE640000u, 34u}, // ett -> Ital
+ {0xD2640000u, 45u}, // etu -> Latn
+ {0xDE640000u, 45u}, // etx -> Latn
+ {0x65750000u, 45u}, // eu -> Latn
+ {0xBAC40000u, 45u}, // ewo -> Latn
+ {0xCEE40000u, 45u}, // ext -> Latn
+ {0x83240000u, 45u}, // eza -> Latn
{0x66610000u, 2u}, // fa -> Arab
- {0x80050000u, 46u}, // faa -> Latn
- {0x84050000u, 46u}, // fab -> Latn
- {0x98050000u, 46u}, // fag -> Latn
- {0xA0050000u, 46u}, // fai -> Latn
- {0xB4050000u, 46u}, // fan -> Latn
- {0x66660000u, 46u}, // ff -> Latn
- {0xA0A50000u, 46u}, // ffi -> Latn
- {0xB0A50000u, 46u}, // ffm -> Latn
- {0x66690000u, 46u}, // fi -> Latn
+ {0x80050000u, 45u}, // faa -> Latn
+ {0x84050000u, 45u}, // fab -> Latn
+ {0x98050000u, 45u}, // fag -> Latn
+ {0xA0050000u, 45u}, // fai -> Latn
+ {0xB4050000u, 45u}, // fan -> Latn
+ {0x66660000u, 45u}, // ff -> Latn
+ {0xA0A50000u, 45u}, // ffi -> Latn
+ {0xB0A50000u, 45u}, // ffm -> Latn
+ {0x66690000u, 45u}, // fi -> Latn
{0x81050000u, 2u}, // fia -> Arab
- {0xAD050000u, 46u}, // fil -> Latn
- {0xCD050000u, 46u}, // fit -> Latn
- {0x666A0000u, 46u}, // fj -> Latn
- {0xC5650000u, 46u}, // flr -> Latn
- {0xBD850000u, 46u}, // fmp -> Latn
- {0x666F0000u, 46u}, // fo -> Latn
- {0x8DC50000u, 46u}, // fod -> Latn
- {0xB5C50000u, 46u}, // fon -> Latn
- {0xC5C50000u, 46u}, // for -> Latn
- {0x91E50000u, 46u}, // fpe -> Latn
- {0xCA050000u, 46u}, // fqs -> Latn
- {0x66720000u, 46u}, // fr -> Latn
- {0x8A250000u, 46u}, // frc -> Latn
- {0xBE250000u, 46u}, // frp -> Latn
- {0xC6250000u, 46u}, // frr -> Latn
- {0xCA250000u, 46u}, // frs -> Latn
+ {0xAD050000u, 45u}, // fil -> Latn
+ {0xCD050000u, 45u}, // fit -> Latn
+ {0x666A0000u, 45u}, // fj -> Latn
+ {0xC5650000u, 45u}, // flr -> Latn
+ {0xBD850000u, 45u}, // fmp -> Latn
+ {0x666F0000u, 45u}, // fo -> Latn
+ {0x8DC50000u, 45u}, // fod -> Latn
+ {0xB5C50000u, 45u}, // fon -> Latn
+ {0xC5C50000u, 45u}, // for -> Latn
+ {0x91E50000u, 45u}, // fpe -> Latn
+ {0xCA050000u, 45u}, // fqs -> Latn
+ {0x66720000u, 45u}, // fr -> Latn
+ {0x8A250000u, 45u}, // frc -> Latn
+ {0xBE250000u, 45u}, // frp -> Latn
+ {0xC6250000u, 45u}, // frr -> Latn
+ {0xCA250000u, 45u}, // frs -> Latn
{0x86850000u, 2u}, // fub -> Arab
- {0x8E850000u, 46u}, // fud -> Latn
- {0x92850000u, 46u}, // fue -> Latn
- {0x96850000u, 46u}, // fuf -> Latn
- {0x9E850000u, 46u}, // fuh -> Latn
- {0xC2850000u, 46u}, // fuq -> Latn
- {0xC6850000u, 46u}, // fur -> Latn
- {0xD6850000u, 46u}, // fuv -> Latn
- {0xE2850000u, 46u}, // fuy -> Latn
- {0xC6A50000u, 46u}, // fvr -> Latn
- {0x66790000u, 46u}, // fy -> Latn
- {0x67610000u, 46u}, // ga -> Latn
- {0x80060000u, 46u}, // gaa -> Latn
- {0x94060000u, 46u}, // gaf -> Latn
- {0x98060000u, 46u}, // gag -> Latn
- {0x9C060000u, 46u}, // gah -> Latn
- {0xA4060000u, 46u}, // gaj -> Latn
- {0xB0060000u, 46u}, // gam -> Latn
+ {0x8E850000u, 45u}, // fud -> Latn
+ {0x92850000u, 45u}, // fue -> Latn
+ {0x96850000u, 45u}, // fuf -> Latn
+ {0x9E850000u, 45u}, // fuh -> Latn
+ {0xC2850000u, 45u}, // fuq -> Latn
+ {0xC6850000u, 45u}, // fur -> Latn
+ {0xD6850000u, 45u}, // fuv -> Latn
+ {0xE2850000u, 45u}, // fuy -> Latn
+ {0xC6A50000u, 45u}, // fvr -> Latn
+ {0x66790000u, 45u}, // fy -> Latn
+ {0x67610000u, 45u}, // ga -> Latn
+ {0x80060000u, 45u}, // gaa -> Latn
+ {0x94060000u, 45u}, // gaf -> Latn
+ {0x98060000u, 45u}, // gag -> Latn
+ {0x9C060000u, 45u}, // gah -> Latn
+ {0xA4060000u, 45u}, // gaj -> Latn
+ {0xB0060000u, 45u}, // gam -> Latn
{0xB4060000u, 29u}, // gan -> Hans
- {0xD8060000u, 46u}, // gaw -> Latn
- {0xE0060000u, 46u}, // gay -> Latn
- {0x80260000u, 46u}, // gba -> Latn
- {0x94260000u, 46u}, // gbf -> Latn
+ {0xD8060000u, 45u}, // gaw -> Latn
+ {0xE0060000u, 45u}, // gay -> Latn
+ {0x80260000u, 45u}, // gba -> Latn
+ {0x94260000u, 45u}, // gbf -> Latn
{0xB0260000u, 19u}, // gbm -> Deva
- {0xE0260000u, 46u}, // gby -> Latn
+ {0xE0260000u, 45u}, // gby -> Latn
{0xE4260000u, 2u}, // gbz -> Arab
- {0xC4460000u, 46u}, // gcr -> Latn
- {0x67640000u, 46u}, // gd -> Latn
- {0x90660000u, 46u}, // gde -> Latn
- {0xB4660000u, 46u}, // gdn -> Latn
- {0xC4660000u, 46u}, // gdr -> Latn
- {0x84860000u, 46u}, // geb -> Latn
- {0xA4860000u, 46u}, // gej -> Latn
- {0xAC860000u, 46u}, // gel -> Latn
+ {0xC4460000u, 45u}, // gcr -> Latn
+ {0x67640000u, 45u}, // gd -> Latn
+ {0x90660000u, 45u}, // gde -> Latn
+ {0xB4660000u, 45u}, // gdn -> Latn
+ {0xC4660000u, 45u}, // gdr -> Latn
+ {0x84860000u, 45u}, // geb -> Latn
+ {0xA4860000u, 45u}, // gej -> Latn
+ {0xAC860000u, 45u}, // gel -> Latn
{0xE4860000u, 21u}, // gez -> Ethi
- {0xA8A60000u, 46u}, // gfk -> Latn
+ {0xA8A60000u, 45u}, // gfk -> Latn
{0xB4C60000u, 19u}, // ggn -> Deva
- {0xC8E60000u, 46u}, // ghs -> Latn
- {0xAD060000u, 46u}, // gil -> Latn
- {0xB1060000u, 46u}, // gim -> Latn
+ {0xC8E60000u, 45u}, // ghs -> Latn
+ {0xAD060000u, 45u}, // gil -> Latn
+ {0xB1060000u, 45u}, // gim -> Latn
{0xA9260000u, 2u}, // gjk -> Arab
- {0xB5260000u, 46u}, // gjn -> Latn
+ {0xB5260000u, 45u}, // gjn -> Latn
{0xD1260000u, 2u}, // gju -> Arab
- {0xB5460000u, 46u}, // gkn -> Latn
- {0xBD460000u, 46u}, // gkp -> Latn
- {0x676C0000u, 46u}, // gl -> Latn
+ {0xB5460000u, 45u}, // gkn -> Latn
+ {0xBD460000u, 45u}, // gkp -> Latn
+ {0x676C0000u, 45u}, // gl -> Latn
{0xA9660000u, 2u}, // glk -> Arab
- {0xB1860000u, 46u}, // gmm -> Latn
+ {0xB1860000u, 45u}, // gmm -> Latn
{0xD5860000u, 21u}, // gmv -> Ethi
- {0x676E0000u, 46u}, // gn -> Latn
- {0x8DA60000u, 46u}, // gnd -> Latn
- {0x99A60000u, 46u}, // gng -> Latn
- {0x8DC60000u, 46u}, // god -> Latn
+ {0x676E0000u, 45u}, // gn -> Latn
+ {0x8DA60000u, 45u}, // gnd -> Latn
+ {0x99A60000u, 45u}, // gng -> Latn
+ {0x8DC60000u, 45u}, // god -> Latn
{0x95C60000u, 21u}, // gof -> Ethi
- {0xA1C60000u, 46u}, // goi -> Latn
+ {0xA1C60000u, 45u}, // goi -> Latn
{0xB1C60000u, 19u}, // gom -> Deva
- {0xB5C60000u, 88u}, // gon -> Telu
- {0xC5C60000u, 46u}, // gor -> Latn
- {0xC9C60000u, 46u}, // gos -> Latn
+ {0xB5C60000u, 89u}, // gon -> Telu
+ {0xC5C60000u, 45u}, // gor -> Latn
+ {0xC9C60000u, 45u}, // gos -> Latn
{0xCDC60000u, 25u}, // got -> Goth
- {0x86260000u, 46u}, // grb -> Latn
+ {0x86260000u, 45u}, // grb -> Latn
{0x8A260000u, 17u}, // grc -> Cprt
{0xCE260000u, 8u}, // grt -> Beng
- {0xDA260000u, 46u}, // grw -> Latn
- {0xDA460000u, 46u}, // gsw -> Latn
+ {0xDA260000u, 45u}, // grw -> Latn
+ {0xDA460000u, 45u}, // gsw -> Latn
{0x67750000u, 27u}, // gu -> Gujr
- {0x86860000u, 46u}, // gub -> Latn
- {0x8A860000u, 46u}, // guc -> Latn
- {0x8E860000u, 46u}, // gud -> Latn
- {0xC6860000u, 46u}, // gur -> Latn
- {0xDA860000u, 46u}, // guw -> Latn
- {0xDE860000u, 46u}, // gux -> Latn
- {0xE6860000u, 46u}, // guz -> Latn
- {0x67760000u, 46u}, // gv -> Latn
- {0x96A60000u, 46u}, // gvf -> Latn
+ {0x86860000u, 45u}, // gub -> Latn
+ {0x8A860000u, 45u}, // guc -> Latn
+ {0x8E860000u, 45u}, // gud -> Latn
+ {0xC6860000u, 45u}, // gur -> Latn
+ {0xDA860000u, 45u}, // guw -> Latn
+ {0xDE860000u, 45u}, // gux -> Latn
+ {0xE6860000u, 45u}, // guz -> Latn
+ {0x67760000u, 45u}, // gv -> Latn
+ {0x96A60000u, 45u}, // gvf -> Latn
{0xC6A60000u, 19u}, // gvr -> Deva
- {0xCAA60000u, 46u}, // gvs -> Latn
+ {0xCAA60000u, 45u}, // gvs -> Latn
{0x8AC60000u, 2u}, // gwc -> Arab
- {0xA2C60000u, 46u}, // gwi -> Latn
+ {0xA2C60000u, 45u}, // gwi -> Latn
{0xCEC60000u, 2u}, // gwt -> Arab
- {0xA3060000u, 46u}, // gyi -> Latn
- {0x68610000u, 46u}, // ha -> Latn
+ {0xA3060000u, 45u}, // gyi -> Latn
+ {0x68610000u, 45u}, // ha -> Latn
{0x6861434Du, 2u}, // ha-CM -> Arab
{0x68615344u, 2u}, // ha-SD -> Arab
- {0x98070000u, 46u}, // hag -> Latn
+ {0x98070000u, 45u}, // hag -> Latn
{0xA8070000u, 29u}, // hak -> Hans
- {0xB0070000u, 46u}, // ham -> Latn
- {0xD8070000u, 46u}, // haw -> Latn
+ {0xB0070000u, 45u}, // ham -> Latn
+ {0xD8070000u, 45u}, // haw -> Latn
{0xE4070000u, 2u}, // haz -> Arab
- {0x84270000u, 46u}, // hbb -> Latn
+ {0x84270000u, 45u}, // hbb -> Latn
{0xE0670000u, 21u}, // hdy -> Ethi
{0x68650000u, 31u}, // he -> Hebr
- {0xE0E70000u, 46u}, // hhy -> Latn
+ {0xE0E70000u, 45u}, // hhy -> Latn
{0x68690000u, 19u}, // hi -> Deva
- {0x81070000u, 46u}, // hia -> Latn
- {0x95070000u, 46u}, // hif -> Latn
- {0x99070000u, 46u}, // hig -> Latn
- {0x9D070000u, 46u}, // hih -> Latn
- {0xAD070000u, 46u}, // hil -> Latn
- {0x81670000u, 46u}, // hla -> Latn
+ {0x81070000u, 45u}, // hia -> Latn
+ {0x95070000u, 45u}, // hif -> Latn
+ {0x99070000u, 45u}, // hig -> Latn
+ {0x9D070000u, 45u}, // hih -> Latn
+ {0xAD070000u, 45u}, // hil -> Latn
+ {0x81670000u, 45u}, // hla -> Latn
{0xD1670000u, 32u}, // hlu -> Hluw
{0x8D870000u, 71u}, // hmd -> Plrd
- {0xCD870000u, 46u}, // hmt -> Latn
+ {0xCD870000u, 45u}, // hmt -> Latn
{0x8DA70000u, 2u}, // hnd -> Arab
{0x91A70000u, 19u}, // hne -> Deva
- {0xA5A70000u, 33u}, // hnj -> Hmng
- {0xB5A70000u, 46u}, // hnn -> Latn
+ {0xA5A70000u, 33u}, // hnj -> Hmnp
+ {0xB5A70000u, 45u}, // hnn -> Latn
{0xB9A70000u, 2u}, // hno -> Arab
- {0x686F0000u, 46u}, // ho -> Latn
+ {0x686F0000u, 45u}, // ho -> Latn
{0x89C70000u, 19u}, // hoc -> Deva
{0xA5C70000u, 19u}, // hoj -> Deva
- {0xCDC70000u, 46u}, // hot -> Latn
- {0x68720000u, 46u}, // hr -> Latn
- {0x86470000u, 46u}, // hsb -> Latn
+ {0xCDC70000u, 45u}, // hot -> Latn
+ {0x68720000u, 45u}, // hr -> Latn
+ {0x86470000u, 45u}, // hsb -> Latn
{0xB6470000u, 29u}, // hsn -> Hans
- {0x68740000u, 46u}, // ht -> Latn
- {0x68750000u, 46u}, // hu -> Latn
- {0xA2870000u, 46u}, // hui -> Latn
+ {0x68740000u, 45u}, // ht -> Latn
+ {0x68750000u, 45u}, // hu -> Latn
+ {0xA2870000u, 45u}, // hui -> Latn
{0x68790000u, 4u}, // hy -> Armn
- {0x687A0000u, 46u}, // hz -> Latn
- {0x69610000u, 46u}, // ia -> Latn
- {0xB4080000u, 46u}, // ian -> Latn
- {0xC4080000u, 46u}, // iar -> Latn
- {0x80280000u, 46u}, // iba -> Latn
- {0x84280000u, 46u}, // ibb -> Latn
- {0xE0280000u, 46u}, // iby -> Latn
- {0x80480000u, 46u}, // ica -> Latn
- {0x9C480000u, 46u}, // ich -> Latn
- {0x69640000u, 46u}, // id -> Latn
- {0x8C680000u, 46u}, // idd -> Latn
- {0xA0680000u, 46u}, // idi -> Latn
- {0xD0680000u, 46u}, // idu -> Latn
- {0x90A80000u, 46u}, // ife -> Latn
- {0x69670000u, 46u}, // ig -> Latn
- {0x84C80000u, 46u}, // igb -> Latn
- {0x90C80000u, 46u}, // ige -> Latn
- {0x69690000u, 98u}, // ii -> Yiii
- {0xA5280000u, 46u}, // ijj -> Latn
- {0x696B0000u, 46u}, // ik -> Latn
- {0xA9480000u, 46u}, // ikk -> Latn
- {0xCD480000u, 46u}, // ikt -> Latn
- {0xD9480000u, 46u}, // ikw -> Latn
- {0xDD480000u, 46u}, // ikx -> Latn
- {0xB9680000u, 46u}, // ilo -> Latn
- {0xB9880000u, 46u}, // imo -> Latn
- {0x696E0000u, 46u}, // in -> Latn
+ {0x687A0000u, 45u}, // hz -> Latn
+ {0x69610000u, 45u}, // ia -> Latn
+ {0xB4080000u, 45u}, // ian -> Latn
+ {0xC4080000u, 45u}, // iar -> Latn
+ {0x80280000u, 45u}, // iba -> Latn
+ {0x84280000u, 45u}, // ibb -> Latn
+ {0xE0280000u, 45u}, // iby -> Latn
+ {0x80480000u, 45u}, // ica -> Latn
+ {0x9C480000u, 45u}, // ich -> Latn
+ {0x69640000u, 45u}, // id -> Latn
+ {0x8C680000u, 45u}, // idd -> Latn
+ {0xA0680000u, 45u}, // idi -> Latn
+ {0xD0680000u, 45u}, // idu -> Latn
+ {0x90A80000u, 45u}, // ife -> Latn
+ {0x69670000u, 45u}, // ig -> Latn
+ {0x84C80000u, 45u}, // igb -> Latn
+ {0x90C80000u, 45u}, // ige -> Latn
+ {0x69690000u, 101u}, // ii -> Yiii
+ {0xA5280000u, 45u}, // ijj -> Latn
+ {0x696B0000u, 45u}, // ik -> Latn
+ {0xA9480000u, 45u}, // ikk -> Latn
+ {0xCD480000u, 45u}, // ikt -> Latn
+ {0xD9480000u, 45u}, // ikw -> Latn
+ {0xDD480000u, 45u}, // ikx -> Latn
+ {0xB9680000u, 45u}, // ilo -> Latn
+ {0xB9880000u, 45u}, // imo -> Latn
+ {0x696E0000u, 45u}, // in -> Latn
{0x9DA80000u, 18u}, // inh -> Cyrl
- {0x696F0000u, 46u}, // io -> Latn
- {0xD1C80000u, 46u}, // iou -> Latn
- {0xA2280000u, 46u}, // iri -> Latn
- {0x69730000u, 46u}, // is -> Latn
- {0x69740000u, 46u}, // it -> Latn
+ {0x696F0000u, 45u}, // io -> Latn
+ {0xD1C80000u, 45u}, // iou -> Latn
+ {0xA2280000u, 45u}, // iri -> Latn
+ {0x69730000u, 45u}, // is -> Latn
+ {0x69740000u, 45u}, // it -> Latn
{0x69750000u, 11u}, // iu -> Cans
{0x69770000u, 31u}, // iw -> Hebr
- {0xB2C80000u, 46u}, // iwm -> Latn
- {0xCAC80000u, 46u}, // iws -> Latn
- {0x9F280000u, 46u}, // izh -> Latn
- {0xA3280000u, 46u}, // izi -> Latn
- {0x6A610000u, 36u}, // ja -> Jpan
- {0x84090000u, 46u}, // jab -> Latn
- {0xB0090000u, 46u}, // jam -> Latn
- {0xC4090000u, 46u}, // jar -> Latn
- {0xB8290000u, 46u}, // jbo -> Latn
- {0xD0290000u, 46u}, // jbu -> Latn
- {0xB4890000u, 46u}, // jen -> Latn
- {0xA8C90000u, 46u}, // jgk -> Latn
- {0xB8C90000u, 46u}, // jgo -> Latn
+ {0xB2C80000u, 45u}, // iwm -> Latn
+ {0xCAC80000u, 45u}, // iws -> Latn
+ {0x9F280000u, 45u}, // izh -> Latn
+ {0xA3280000u, 45u}, // izi -> Latn
+ {0x6A610000u, 35u}, // ja -> Jpan
+ {0x84090000u, 45u}, // jab -> Latn
+ {0xB0090000u, 45u}, // jam -> Latn
+ {0xC4090000u, 45u}, // jar -> Latn
+ {0xB8290000u, 45u}, // jbo -> Latn
+ {0xD0290000u, 45u}, // jbu -> Latn
+ {0xB4890000u, 45u}, // jen -> Latn
+ {0xA8C90000u, 45u}, // jgk -> Latn
+ {0xB8C90000u, 45u}, // jgo -> Latn
{0x6A690000u, 31u}, // ji -> Hebr
- {0x85090000u, 46u}, // jib -> Latn
- {0x89890000u, 46u}, // jmc -> Latn
+ {0x85090000u, 45u}, // jib -> Latn
+ {0x89890000u, 45u}, // jmc -> Latn
{0xAD890000u, 19u}, // jml -> Deva
- {0x82290000u, 46u}, // jra -> Latn
- {0xCE890000u, 46u}, // jut -> Latn
- {0x6A760000u, 46u}, // jv -> Latn
- {0x6A770000u, 46u}, // jw -> Latn
+ {0x82290000u, 45u}, // jra -> Latn
+ {0xCE890000u, 45u}, // jut -> Latn
+ {0x6A760000u, 45u}, // jv -> Latn
+ {0x6A770000u, 45u}, // jw -> Latn
{0x6B610000u, 22u}, // ka -> Geor
{0x800A0000u, 18u}, // kaa -> Cyrl
- {0x840A0000u, 46u}, // kab -> Latn
- {0x880A0000u, 46u}, // kac -> Latn
- {0x8C0A0000u, 46u}, // kad -> Latn
- {0xA00A0000u, 46u}, // kai -> Latn
- {0xA40A0000u, 46u}, // kaj -> Latn
- {0xB00A0000u, 46u}, // kam -> Latn
- {0xB80A0000u, 46u}, // kao -> Latn
+ {0x840A0000u, 45u}, // kab -> Latn
+ {0x880A0000u, 45u}, // kac -> Latn
+ {0x8C0A0000u, 45u}, // kad -> Latn
+ {0xA00A0000u, 45u}, // kai -> Latn
+ {0xA40A0000u, 45u}, // kaj -> Latn
+ {0xB00A0000u, 45u}, // kam -> Latn
+ {0xB80A0000u, 45u}, // kao -> Latn
{0x8C2A0000u, 18u}, // kbd -> Cyrl
- {0xB02A0000u, 46u}, // kbm -> Latn
- {0xBC2A0000u, 46u}, // kbp -> Latn
- {0xC02A0000u, 46u}, // kbq -> Latn
- {0xDC2A0000u, 46u}, // kbx -> Latn
+ {0xB02A0000u, 45u}, // kbm -> Latn
+ {0xBC2A0000u, 45u}, // kbp -> Latn
+ {0xC02A0000u, 45u}, // kbq -> Latn
+ {0xDC2A0000u, 45u}, // kbx -> Latn
{0xE02A0000u, 2u}, // kby -> Arab
- {0x984A0000u, 46u}, // kcg -> Latn
- {0xA84A0000u, 46u}, // kck -> Latn
- {0xAC4A0000u, 46u}, // kcl -> Latn
- {0xCC4A0000u, 46u}, // kct -> Latn
- {0x906A0000u, 46u}, // kde -> Latn
- {0x9C6A0000u, 2u}, // kdh -> Arab
- {0xAC6A0000u, 46u}, // kdl -> Latn
- {0xCC6A0000u, 91u}, // kdt -> Thai
- {0x808A0000u, 46u}, // kea -> Latn
- {0xB48A0000u, 46u}, // ken -> Latn
- {0xE48A0000u, 46u}, // kez -> Latn
- {0xB8AA0000u, 46u}, // kfo -> Latn
+ {0x984A0000u, 45u}, // kcg -> Latn
+ {0xA84A0000u, 45u}, // kck -> Latn
+ {0xAC4A0000u, 45u}, // kcl -> Latn
+ {0xCC4A0000u, 45u}, // kct -> Latn
+ {0x906A0000u, 45u}, // kde -> Latn
+ {0x9C6A0000u, 45u}, // kdh -> Latn
+ {0xAC6A0000u, 45u}, // kdl -> Latn
+ {0xCC6A0000u, 92u}, // kdt -> Thai
+ {0x808A0000u, 45u}, // kea -> Latn
+ {0xB48A0000u, 45u}, // ken -> Latn
+ {0xE48A0000u, 45u}, // kez -> Latn
+ {0xB8AA0000u, 45u}, // kfo -> Latn
{0xC4AA0000u, 19u}, // kfr -> Deva
{0xE0AA0000u, 19u}, // kfy -> Deva
- {0x6B670000u, 46u}, // kg -> Latn
- {0x90CA0000u, 46u}, // kge -> Latn
- {0x94CA0000u, 46u}, // kgf -> Latn
- {0xBCCA0000u, 46u}, // kgp -> Latn
- {0x80EA0000u, 46u}, // kha -> Latn
- {0x84EA0000u, 84u}, // khb -> Talu
+ {0x6B670000u, 45u}, // kg -> Latn
+ {0x90CA0000u, 45u}, // kge -> Latn
+ {0x94CA0000u, 45u}, // kgf -> Latn
+ {0xBCCA0000u, 45u}, // kgp -> Latn
+ {0x80EA0000u, 45u}, // kha -> Latn
+ {0x84EA0000u, 85u}, // khb -> Talu
{0xB4EA0000u, 19u}, // khn -> Deva
- {0xC0EA0000u, 46u}, // khq -> Latn
- {0xC8EA0000u, 46u}, // khs -> Latn
- {0xCCEA0000u, 59u}, // kht -> Mymr
+ {0xC0EA0000u, 45u}, // khq -> Latn
+ {0xC8EA0000u, 45u}, // khs -> Latn
+ {0xCCEA0000u, 58u}, // kht -> Mymr
{0xD8EA0000u, 2u}, // khw -> Arab
- {0xE4EA0000u, 46u}, // khz -> Latn
- {0x6B690000u, 46u}, // ki -> Latn
- {0xA50A0000u, 46u}, // kij -> Latn
- {0xD10A0000u, 46u}, // kiu -> Latn
- {0xD90A0000u, 46u}, // kiw -> Latn
- {0x6B6A0000u, 46u}, // kj -> Latn
- {0x8D2A0000u, 46u}, // kjd -> Latn
- {0x992A0000u, 45u}, // kjg -> Laoo
- {0xC92A0000u, 46u}, // kjs -> Latn
- {0xE12A0000u, 46u}, // kjy -> Latn
+ {0xE4EA0000u, 45u}, // khz -> Latn
+ {0x6B690000u, 45u}, // ki -> Latn
+ {0xA50A0000u, 45u}, // kij -> Latn
+ {0xD10A0000u, 45u}, // kiu -> Latn
+ {0xD90A0000u, 45u}, // kiw -> Latn
+ {0x6B6A0000u, 45u}, // kj -> Latn
+ {0x8D2A0000u, 45u}, // kjd -> Latn
+ {0x992A0000u, 44u}, // kjg -> Laoo
+ {0xC92A0000u, 45u}, // kjs -> Latn
+ {0xE12A0000u, 45u}, // kjy -> Latn
{0x6B6B0000u, 18u}, // kk -> Cyrl
{0x6B6B4146u, 2u}, // kk-AF -> Arab
{0x6B6B434Eu, 2u}, // kk-CN -> Arab
{0x6B6B4952u, 2u}, // kk-IR -> Arab
{0x6B6B4D4Eu, 2u}, // kk-MN -> Arab
- {0x894A0000u, 46u}, // kkc -> Latn
- {0xA54A0000u, 46u}, // kkj -> Latn
- {0x6B6C0000u, 46u}, // kl -> Latn
- {0xB56A0000u, 46u}, // kln -> Latn
- {0xC16A0000u, 46u}, // klq -> Latn
- {0xCD6A0000u, 46u}, // klt -> Latn
- {0xDD6A0000u, 46u}, // klx -> Latn
- {0x6B6D0000u, 40u}, // km -> Khmr
- {0x858A0000u, 46u}, // kmb -> Latn
- {0x9D8A0000u, 46u}, // kmh -> Latn
- {0xB98A0000u, 46u}, // kmo -> Latn
- {0xC98A0000u, 46u}, // kms -> Latn
- {0xD18A0000u, 46u}, // kmu -> Latn
- {0xD98A0000u, 46u}, // kmw -> Latn
- {0x6B6E0000u, 42u}, // kn -> Knda
- {0x95AA0000u, 46u}, // knf -> Latn
- {0xBDAA0000u, 46u}, // knp -> Latn
- {0x6B6F0000u, 43u}, // ko -> Kore
+ {0x894A0000u, 45u}, // kkc -> Latn
+ {0xA54A0000u, 45u}, // kkj -> Latn
+ {0x6B6C0000u, 45u}, // kl -> Latn
+ {0xB56A0000u, 45u}, // kln -> Latn
+ {0xC16A0000u, 45u}, // klq -> Latn
+ {0xCD6A0000u, 45u}, // klt -> Latn
+ {0xDD6A0000u, 45u}, // klx -> Latn
+ {0x6B6D0000u, 39u}, // km -> Khmr
+ {0x858A0000u, 45u}, // kmb -> Latn
+ {0x9D8A0000u, 45u}, // kmh -> Latn
+ {0xB98A0000u, 45u}, // kmo -> Latn
+ {0xC98A0000u, 45u}, // kms -> Latn
+ {0xD18A0000u, 45u}, // kmu -> Latn
+ {0xD98A0000u, 45u}, // kmw -> Latn
+ {0x6B6E0000u, 41u}, // kn -> Knda
+ {0x95AA0000u, 45u}, // knf -> Latn
+ {0xBDAA0000u, 45u}, // knp -> Latn
+ {0x6B6F0000u, 42u}, // ko -> Kore
{0xA1CA0000u, 18u}, // koi -> Cyrl
{0xA9CA0000u, 19u}, // kok -> Deva
- {0xADCA0000u, 46u}, // kol -> Latn
- {0xC9CA0000u, 46u}, // kos -> Latn
- {0xE5CA0000u, 46u}, // koz -> Latn
- {0x91EA0000u, 46u}, // kpe -> Latn
- {0x95EA0000u, 46u}, // kpf -> Latn
- {0xB9EA0000u, 46u}, // kpo -> Latn
- {0xC5EA0000u, 46u}, // kpr -> Latn
- {0xDDEA0000u, 46u}, // kpx -> Latn
- {0x860A0000u, 46u}, // kqb -> Latn
- {0x960A0000u, 46u}, // kqf -> Latn
- {0xCA0A0000u, 46u}, // kqs -> Latn
+ {0xADCA0000u, 45u}, // kol -> Latn
+ {0xC9CA0000u, 45u}, // kos -> Latn
+ {0xE5CA0000u, 45u}, // koz -> Latn
+ {0x91EA0000u, 45u}, // kpe -> Latn
+ {0x95EA0000u, 45u}, // kpf -> Latn
+ {0xB9EA0000u, 45u}, // kpo -> Latn
+ {0xC5EA0000u, 45u}, // kpr -> Latn
+ {0xDDEA0000u, 45u}, // kpx -> Latn
+ {0x860A0000u, 45u}, // kqb -> Latn
+ {0x960A0000u, 45u}, // kqf -> Latn
+ {0xCA0A0000u, 45u}, // kqs -> Latn
{0xE20A0000u, 21u}, // kqy -> Ethi
- {0x6B720000u, 46u}, // kr -> Latn
+ {0x6B720000u, 45u}, // kr -> Latn
{0x8A2A0000u, 18u}, // krc -> Cyrl
- {0xA22A0000u, 46u}, // kri -> Latn
- {0xA62A0000u, 46u}, // krj -> Latn
- {0xAE2A0000u, 46u}, // krl -> Latn
- {0xCA2A0000u, 46u}, // krs -> Latn
+ {0xA22A0000u, 45u}, // kri -> Latn
+ {0xA62A0000u, 45u}, // krj -> Latn
+ {0xAE2A0000u, 45u}, // krl -> Latn
+ {0xCA2A0000u, 45u}, // krs -> Latn
{0xD22A0000u, 19u}, // kru -> Deva
{0x6B730000u, 2u}, // ks -> Arab
- {0x864A0000u, 46u}, // ksb -> Latn
- {0x8E4A0000u, 46u}, // ksd -> Latn
- {0x964A0000u, 46u}, // ksf -> Latn
- {0x9E4A0000u, 46u}, // ksh -> Latn
- {0xA64A0000u, 46u}, // ksj -> Latn
- {0xC64A0000u, 46u}, // ksr -> Latn
+ {0x864A0000u, 45u}, // ksb -> Latn
+ {0x8E4A0000u, 45u}, // ksd -> Latn
+ {0x964A0000u, 45u}, // ksf -> Latn
+ {0x9E4A0000u, 45u}, // ksh -> Latn
+ {0xA64A0000u, 45u}, // ksj -> Latn
+ {0xC64A0000u, 45u}, // ksr -> Latn
{0x866A0000u, 21u}, // ktb -> Ethi
- {0xB26A0000u, 46u}, // ktm -> Latn
- {0xBA6A0000u, 46u}, // kto -> Latn
- {0xC66A0000u, 46u}, // ktr -> Latn
- {0x6B750000u, 46u}, // ku -> Latn
+ {0xB26A0000u, 45u}, // ktm -> Latn
+ {0xBA6A0000u, 45u}, // kto -> Latn
+ {0xC66A0000u, 45u}, // ktr -> Latn
+ {0x6B750000u, 45u}, // ku -> Latn
{0x6B754952u, 2u}, // ku-IR -> Arab
{0x6B754C42u, 2u}, // ku-LB -> Arab
- {0x868A0000u, 46u}, // kub -> Latn
- {0x8E8A0000u, 46u}, // kud -> Latn
- {0x928A0000u, 46u}, // kue -> Latn
- {0xA68A0000u, 46u}, // kuj -> Latn
+ {0x868A0000u, 45u}, // kub -> Latn
+ {0x8E8A0000u, 45u}, // kud -> Latn
+ {0x928A0000u, 45u}, // kue -> Latn
+ {0xA68A0000u, 45u}, // kuj -> Latn
{0xB28A0000u, 18u}, // kum -> Cyrl
- {0xB68A0000u, 46u}, // kun -> Latn
- {0xBE8A0000u, 46u}, // kup -> Latn
- {0xCA8A0000u, 46u}, // kus -> Latn
+ {0xB68A0000u, 45u}, // kun -> Latn
+ {0xBE8A0000u, 45u}, // kup -> Latn
+ {0xCA8A0000u, 45u}, // kus -> Latn
{0x6B760000u, 18u}, // kv -> Cyrl
- {0x9AAA0000u, 46u}, // kvg -> Latn
- {0xC6AA0000u, 46u}, // kvr -> Latn
+ {0x9AAA0000u, 45u}, // kvg -> Latn
+ {0xC6AA0000u, 45u}, // kvr -> Latn
{0xDEAA0000u, 2u}, // kvx -> Arab
- {0x6B770000u, 46u}, // kw -> Latn
- {0xA6CA0000u, 46u}, // kwj -> Latn
- {0xBACA0000u, 46u}, // kwo -> Latn
- {0xC2CA0000u, 46u}, // kwq -> Latn
- {0x82EA0000u, 46u}, // kxa -> Latn
+ {0x6B770000u, 45u}, // kw -> Latn
+ {0xA6CA0000u, 45u}, // kwj -> Latn
+ {0xBACA0000u, 45u}, // kwo -> Latn
+ {0xC2CA0000u, 45u}, // kwq -> Latn
+ {0x82EA0000u, 45u}, // kxa -> Latn
{0x8AEA0000u, 21u}, // kxc -> Ethi
- {0x92EA0000u, 46u}, // kxe -> Latn
+ {0x92EA0000u, 45u}, // kxe -> Latn
{0xAEEA0000u, 19u}, // kxl -> Deva
- {0xB2EA0000u, 91u}, // kxm -> Thai
+ {0xB2EA0000u, 92u}, // kxm -> Thai
{0xBEEA0000u, 2u}, // kxp -> Arab
- {0xDAEA0000u, 46u}, // kxw -> Latn
- {0xE6EA0000u, 46u}, // kxz -> Latn
+ {0xDAEA0000u, 45u}, // kxw -> Latn
+ {0xE6EA0000u, 45u}, // kxz -> Latn
{0x6B790000u, 18u}, // ky -> Cyrl
{0x6B79434Eu, 2u}, // ky-CN -> Arab
- {0x6B795452u, 46u}, // ky-TR -> Latn
- {0x930A0000u, 46u}, // kye -> Latn
- {0xDF0A0000u, 46u}, // kyx -> Latn
+ {0x6B795452u, 45u}, // ky-TR -> Latn
+ {0x930A0000u, 45u}, // kye -> Latn
+ {0xDF0A0000u, 45u}, // kyx -> Latn
{0x9F2A0000u, 2u}, // kzh -> Arab
- {0xA72A0000u, 46u}, // kzj -> Latn
- {0xC72A0000u, 46u}, // kzr -> Latn
- {0xCF2A0000u, 46u}, // kzt -> Latn
- {0x6C610000u, 46u}, // la -> Latn
- {0x840B0000u, 48u}, // lab -> Lina
+ {0xA72A0000u, 45u}, // kzj -> Latn
+ {0xC72A0000u, 45u}, // kzr -> Latn
+ {0xCF2A0000u, 45u}, // kzt -> Latn
+ {0x6C610000u, 45u}, // la -> Latn
+ {0x840B0000u, 47u}, // lab -> Lina
{0x8C0B0000u, 31u}, // lad -> Hebr
- {0x980B0000u, 46u}, // lag -> Latn
+ {0x980B0000u, 45u}, // lag -> Latn
{0x9C0B0000u, 2u}, // lah -> Arab
- {0xA40B0000u, 46u}, // laj -> Latn
- {0xC80B0000u, 46u}, // las -> Latn
- {0x6C620000u, 46u}, // lb -> Latn
+ {0xA40B0000u, 45u}, // laj -> Latn
+ {0xC80B0000u, 45u}, // las -> Latn
+ {0x6C620000u, 45u}, // lb -> Latn
{0x902B0000u, 18u}, // lbe -> Cyrl
- {0xD02B0000u, 46u}, // lbu -> Latn
- {0xD82B0000u, 46u}, // lbw -> Latn
- {0xB04B0000u, 46u}, // lcm -> Latn
- {0xBC4B0000u, 91u}, // lcp -> Thai
- {0x846B0000u, 46u}, // ldb -> Latn
- {0x8C8B0000u, 46u}, // led -> Latn
- {0x908B0000u, 46u}, // lee -> Latn
- {0xB08B0000u, 46u}, // lem -> Latn
- {0xBC8B0000u, 47u}, // lep -> Lepc
- {0xC08B0000u, 46u}, // leq -> Latn
- {0xD08B0000u, 46u}, // leu -> Latn
+ {0xD02B0000u, 45u}, // lbu -> Latn
+ {0xD82B0000u, 45u}, // lbw -> Latn
+ {0xB04B0000u, 45u}, // lcm -> Latn
+ {0xBC4B0000u, 92u}, // lcp -> Thai
+ {0x846B0000u, 45u}, // ldb -> Latn
+ {0x8C8B0000u, 45u}, // led -> Latn
+ {0x908B0000u, 45u}, // lee -> Latn
+ {0xB08B0000u, 45u}, // lem -> Latn
+ {0xBC8B0000u, 46u}, // lep -> Lepc
+ {0xC08B0000u, 45u}, // leq -> Latn
+ {0xD08B0000u, 45u}, // leu -> Latn
{0xE48B0000u, 18u}, // lez -> Cyrl
- {0x6C670000u, 46u}, // lg -> Latn
- {0x98CB0000u, 46u}, // lgg -> Latn
- {0x6C690000u, 46u}, // li -> Latn
- {0x810B0000u, 46u}, // lia -> Latn
- {0x8D0B0000u, 46u}, // lid -> Latn
+ {0x6C670000u, 45u}, // lg -> Latn
+ {0x98CB0000u, 45u}, // lgg -> Latn
+ {0x6C690000u, 45u}, // li -> Latn
+ {0x810B0000u, 45u}, // lia -> Latn
+ {0x8D0B0000u, 45u}, // lid -> Latn
{0x950B0000u, 19u}, // lif -> Deva
- {0x990B0000u, 46u}, // lig -> Latn
- {0x9D0B0000u, 46u}, // lih -> Latn
- {0xA50B0000u, 46u}, // lij -> Latn
- {0xC90B0000u, 49u}, // lis -> Lisu
- {0xBD2B0000u, 46u}, // ljp -> Latn
+ {0x990B0000u, 45u}, // lig -> Latn
+ {0x9D0B0000u, 45u}, // lih -> Latn
+ {0xA50B0000u, 45u}, // lij -> Latn
+ {0xC90B0000u, 48u}, // lis -> Lisu
+ {0xBD2B0000u, 45u}, // ljp -> Latn
{0xA14B0000u, 2u}, // lki -> Arab
- {0xCD4B0000u, 46u}, // lkt -> Latn
- {0x916B0000u, 46u}, // lle -> Latn
- {0xB56B0000u, 46u}, // lln -> Latn
- {0xB58B0000u, 88u}, // lmn -> Telu
- {0xB98B0000u, 46u}, // lmo -> Latn
- {0xBD8B0000u, 46u}, // lmp -> Latn
- {0x6C6E0000u, 46u}, // ln -> Latn
- {0xC9AB0000u, 46u}, // lns -> Latn
- {0xD1AB0000u, 46u}, // lnu -> Latn
- {0x6C6F0000u, 45u}, // lo -> Laoo
- {0xA5CB0000u, 46u}, // loj -> Latn
- {0xA9CB0000u, 46u}, // lok -> Latn
- {0xADCB0000u, 46u}, // lol -> Latn
- {0xC5CB0000u, 46u}, // lor -> Latn
- {0xC9CB0000u, 46u}, // los -> Latn
- {0xE5CB0000u, 46u}, // loz -> Latn
+ {0xCD4B0000u, 45u}, // lkt -> Latn
+ {0x916B0000u, 45u}, // lle -> Latn
+ {0xB56B0000u, 45u}, // lln -> Latn
+ {0xB58B0000u, 89u}, // lmn -> Telu
+ {0xB98B0000u, 45u}, // lmo -> Latn
+ {0xBD8B0000u, 45u}, // lmp -> Latn
+ {0x6C6E0000u, 45u}, // ln -> Latn
+ {0xC9AB0000u, 45u}, // lns -> Latn
+ {0xD1AB0000u, 45u}, // lnu -> Latn
+ {0x6C6F0000u, 44u}, // lo -> Laoo
+ {0xA5CB0000u, 45u}, // loj -> Latn
+ {0xA9CB0000u, 45u}, // lok -> Latn
+ {0xADCB0000u, 45u}, // lol -> Latn
+ {0xC5CB0000u, 45u}, // lor -> Latn
+ {0xC9CB0000u, 45u}, // los -> Latn
+ {0xE5CB0000u, 45u}, // loz -> Latn
{0x8A2B0000u, 2u}, // lrc -> Arab
- {0x6C740000u, 46u}, // lt -> Latn
- {0x9A6B0000u, 46u}, // ltg -> Latn
- {0x6C750000u, 46u}, // lu -> Latn
- {0x828B0000u, 46u}, // lua -> Latn
- {0xBA8B0000u, 46u}, // luo -> Latn
- {0xE28B0000u, 46u}, // luy -> Latn
+ {0x6C740000u, 45u}, // lt -> Latn
+ {0x9A6B0000u, 45u}, // ltg -> Latn
+ {0x6C750000u, 45u}, // lu -> Latn
+ {0x828B0000u, 45u}, // lua -> Latn
+ {0xBA8B0000u, 45u}, // luo -> Latn
+ {0xE28B0000u, 45u}, // luy -> Latn
{0xE68B0000u, 2u}, // luz -> Arab
- {0x6C760000u, 46u}, // lv -> Latn
- {0xAECB0000u, 91u}, // lwl -> Thai
+ {0x6C760000u, 45u}, // lv -> Latn
+ {0xAECB0000u, 92u}, // lwl -> Thai
{0x9F2B0000u, 29u}, // lzh -> Hans
- {0xE72B0000u, 46u}, // lzz -> Latn
- {0x8C0C0000u, 46u}, // mad -> Latn
- {0x940C0000u, 46u}, // maf -> Latn
+ {0xE72B0000u, 45u}, // lzz -> Latn
+ {0x8C0C0000u, 45u}, // mad -> Latn
+ {0x940C0000u, 45u}, // maf -> Latn
{0x980C0000u, 19u}, // mag -> Deva
{0xA00C0000u, 19u}, // mai -> Deva
- {0xA80C0000u, 46u}, // mak -> Latn
- {0xB40C0000u, 46u}, // man -> Latn
- {0xB40C474Eu, 61u}, // man-GN -> Nkoo
- {0xC80C0000u, 46u}, // mas -> Latn
- {0xD80C0000u, 46u}, // maw -> Latn
- {0xE40C0000u, 46u}, // maz -> Latn
- {0x9C2C0000u, 46u}, // mbh -> Latn
- {0xB82C0000u, 46u}, // mbo -> Latn
- {0xC02C0000u, 46u}, // mbq -> Latn
- {0xD02C0000u, 46u}, // mbu -> Latn
- {0xD82C0000u, 46u}, // mbw -> Latn
- {0xA04C0000u, 46u}, // mci -> Latn
- {0xBC4C0000u, 46u}, // mcp -> Latn
- {0xC04C0000u, 46u}, // mcq -> Latn
- {0xC44C0000u, 46u}, // mcr -> Latn
- {0xD04C0000u, 46u}, // mcu -> Latn
- {0x806C0000u, 46u}, // mda -> Latn
+ {0xA80C0000u, 45u}, // mak -> Latn
+ {0xB40C0000u, 45u}, // man -> Latn
+ {0xB40C474Eu, 60u}, // man-GN -> Nkoo
+ {0xC80C0000u, 45u}, // mas -> Latn
+ {0xD80C0000u, 45u}, // maw -> Latn
+ {0xE40C0000u, 45u}, // maz -> Latn
+ {0x9C2C0000u, 45u}, // mbh -> Latn
+ {0xB82C0000u, 45u}, // mbo -> Latn
+ {0xC02C0000u, 45u}, // mbq -> Latn
+ {0xD02C0000u, 45u}, // mbu -> Latn
+ {0xD82C0000u, 45u}, // mbw -> Latn
+ {0xA04C0000u, 45u}, // mci -> Latn
+ {0xBC4C0000u, 45u}, // mcp -> Latn
+ {0xC04C0000u, 45u}, // mcq -> Latn
+ {0xC44C0000u, 45u}, // mcr -> Latn
+ {0xD04C0000u, 45u}, // mcu -> Latn
+ {0x806C0000u, 45u}, // mda -> Latn
{0x906C0000u, 2u}, // mde -> Arab
{0x946C0000u, 18u}, // mdf -> Cyrl
- {0x9C6C0000u, 46u}, // mdh -> Latn
- {0xA46C0000u, 46u}, // mdj -> Latn
- {0xC46C0000u, 46u}, // mdr -> Latn
+ {0x9C6C0000u, 45u}, // mdh -> Latn
+ {0xA46C0000u, 45u}, // mdj -> Latn
+ {0xC46C0000u, 45u}, // mdr -> Latn
{0xDC6C0000u, 21u}, // mdx -> Ethi
- {0x8C8C0000u, 46u}, // med -> Latn
- {0x908C0000u, 46u}, // mee -> Latn
- {0xA88C0000u, 46u}, // mek -> Latn
- {0xB48C0000u, 46u}, // men -> Latn
- {0xC48C0000u, 46u}, // mer -> Latn
- {0xCC8C0000u, 46u}, // met -> Latn
- {0xD08C0000u, 46u}, // meu -> Latn
+ {0x8C8C0000u, 45u}, // med -> Latn
+ {0x908C0000u, 45u}, // mee -> Latn
+ {0xA88C0000u, 45u}, // mek -> Latn
+ {0xB48C0000u, 45u}, // men -> Latn
+ {0xC48C0000u, 45u}, // mer -> Latn
+ {0xCC8C0000u, 45u}, // met -> Latn
+ {0xD08C0000u, 45u}, // meu -> Latn
{0x80AC0000u, 2u}, // mfa -> Arab
- {0x90AC0000u, 46u}, // mfe -> Latn
- {0xB4AC0000u, 46u}, // mfn -> Latn
- {0xB8AC0000u, 46u}, // mfo -> Latn
- {0xC0AC0000u, 46u}, // mfq -> Latn
- {0x6D670000u, 46u}, // mg -> Latn
- {0x9CCC0000u, 46u}, // mgh -> Latn
- {0xACCC0000u, 46u}, // mgl -> Latn
- {0xB8CC0000u, 46u}, // mgo -> Latn
+ {0x90AC0000u, 45u}, // mfe -> Latn
+ {0xB4AC0000u, 45u}, // mfn -> Latn
+ {0xB8AC0000u, 45u}, // mfo -> Latn
+ {0xC0AC0000u, 45u}, // mfq -> Latn
+ {0x6D670000u, 45u}, // mg -> Latn
+ {0x9CCC0000u, 45u}, // mgh -> Latn
+ {0xACCC0000u, 45u}, // mgl -> Latn
+ {0xB8CC0000u, 45u}, // mgo -> Latn
{0xBCCC0000u, 19u}, // mgp -> Deva
- {0xE0CC0000u, 46u}, // mgy -> Latn
- {0x6D680000u, 46u}, // mh -> Latn
- {0xA0EC0000u, 46u}, // mhi -> Latn
- {0xACEC0000u, 46u}, // mhl -> Latn
- {0x6D690000u, 46u}, // mi -> Latn
- {0x950C0000u, 46u}, // mif -> Latn
- {0xB50C0000u, 46u}, // min -> Latn
- {0xD90C0000u, 46u}, // miw -> Latn
+ {0xE0CC0000u, 45u}, // mgy -> Latn
+ {0x6D680000u, 45u}, // mh -> Latn
+ {0xA0EC0000u, 45u}, // mhi -> Latn
+ {0xACEC0000u, 45u}, // mhl -> Latn
+ {0x6D690000u, 45u}, // mi -> Latn
+ {0x950C0000u, 45u}, // mif -> Latn
+ {0xB50C0000u, 45u}, // min -> Latn
+ {0xD90C0000u, 45u}, // miw -> Latn
{0x6D6B0000u, 18u}, // mk -> Cyrl
{0xA14C0000u, 2u}, // mki -> Arab
- {0xAD4C0000u, 46u}, // mkl -> Latn
- {0xBD4C0000u, 46u}, // mkp -> Latn
- {0xD94C0000u, 46u}, // mkw -> Latn
- {0x6D6C0000u, 56u}, // ml -> Mlym
- {0x916C0000u, 46u}, // mle -> Latn
- {0xBD6C0000u, 46u}, // mlp -> Latn
- {0xC96C0000u, 46u}, // mls -> Latn
- {0xB98C0000u, 46u}, // mmo -> Latn
- {0xD18C0000u, 46u}, // mmu -> Latn
- {0xDD8C0000u, 46u}, // mmx -> Latn
+ {0xAD4C0000u, 45u}, // mkl -> Latn
+ {0xBD4C0000u, 45u}, // mkp -> Latn
+ {0xD94C0000u, 45u}, // mkw -> Latn
+ {0x6D6C0000u, 55u}, // ml -> Mlym
+ {0x916C0000u, 45u}, // mle -> Latn
+ {0xBD6C0000u, 45u}, // mlp -> Latn
+ {0xC96C0000u, 45u}, // mls -> Latn
+ {0xB98C0000u, 45u}, // mmo -> Latn
+ {0xD18C0000u, 45u}, // mmu -> Latn
+ {0xDD8C0000u, 45u}, // mmx -> Latn
{0x6D6E0000u, 18u}, // mn -> Cyrl
- {0x6D6E434Eu, 57u}, // mn-CN -> Mong
- {0x81AC0000u, 46u}, // mna -> Latn
- {0x95AC0000u, 46u}, // mnf -> Latn
+ {0x6D6E434Eu, 56u}, // mn-CN -> Mong
+ {0x81AC0000u, 45u}, // mna -> Latn
+ {0x95AC0000u, 45u}, // mnf -> Latn
{0xA1AC0000u, 8u}, // mni -> Beng
- {0xD9AC0000u, 59u}, // mnw -> Mymr
- {0x6D6F0000u, 46u}, // mo -> Latn
- {0x81CC0000u, 46u}, // moa -> Latn
- {0x91CC0000u, 46u}, // moe -> Latn
- {0x9DCC0000u, 46u}, // moh -> Latn
- {0xC9CC0000u, 46u}, // mos -> Latn
- {0xDDCC0000u, 46u}, // mox -> Latn
- {0xBDEC0000u, 46u}, // mpp -> Latn
- {0xC9EC0000u, 46u}, // mps -> Latn
- {0xCDEC0000u, 46u}, // mpt -> Latn
- {0xDDEC0000u, 46u}, // mpx -> Latn
- {0xAE0C0000u, 46u}, // mql -> Latn
+ {0xD9AC0000u, 58u}, // mnw -> Mymr
+ {0x6D6F0000u, 45u}, // mo -> Latn
+ {0x81CC0000u, 45u}, // moa -> Latn
+ {0x91CC0000u, 45u}, // moe -> Latn
+ {0x9DCC0000u, 45u}, // moh -> Latn
+ {0xC9CC0000u, 45u}, // mos -> Latn
+ {0xDDCC0000u, 45u}, // mox -> Latn
+ {0xBDEC0000u, 45u}, // mpp -> Latn
+ {0xC9EC0000u, 45u}, // mps -> Latn
+ {0xCDEC0000u, 45u}, // mpt -> Latn
+ {0xDDEC0000u, 45u}, // mpx -> Latn
+ {0xAE0C0000u, 45u}, // mql -> Latn
{0x6D720000u, 19u}, // mr -> Deva
{0x8E2C0000u, 19u}, // mrd -> Deva
{0xA62C0000u, 18u}, // mrj -> Cyrl
- {0xBA2C0000u, 58u}, // mro -> Mroo
- {0x6D730000u, 46u}, // ms -> Latn
+ {0xBA2C0000u, 57u}, // mro -> Mroo
+ {0x6D730000u, 45u}, // ms -> Latn
{0x6D734343u, 2u}, // ms-CC -> Arab
- {0x6D740000u, 46u}, // mt -> Latn
- {0x8A6C0000u, 46u}, // mtc -> Latn
- {0x966C0000u, 46u}, // mtf -> Latn
- {0xA26C0000u, 46u}, // mti -> Latn
+ {0x6D740000u, 45u}, // mt -> Latn
+ {0x8A6C0000u, 45u}, // mtc -> Latn
+ {0x966C0000u, 45u}, // mtf -> Latn
+ {0xA26C0000u, 45u}, // mti -> Latn
{0xC66C0000u, 19u}, // mtr -> Deva
- {0x828C0000u, 46u}, // mua -> Latn
- {0xC68C0000u, 46u}, // mur -> Latn
- {0xCA8C0000u, 46u}, // mus -> Latn
- {0x82AC0000u, 46u}, // mva -> Latn
- {0xB6AC0000u, 46u}, // mvn -> Latn
+ {0x828C0000u, 45u}, // mua -> Latn
+ {0xC68C0000u, 45u}, // mur -> Latn
+ {0xCA8C0000u, 45u}, // mus -> Latn
+ {0x82AC0000u, 45u}, // mva -> Latn
+ {0xB6AC0000u, 45u}, // mvn -> Latn
{0xE2AC0000u, 2u}, // mvy -> Arab
- {0xAACC0000u, 46u}, // mwk -> Latn
+ {0xAACC0000u, 45u}, // mwk -> Latn
{0xC6CC0000u, 19u}, // mwr -> Deva
- {0xD6CC0000u, 46u}, // mwv -> Latn
- {0xDACC0000u, 34u}, // mww -> Hmnp
- {0x8AEC0000u, 46u}, // mxc -> Latn
- {0xB2EC0000u, 46u}, // mxm -> Latn
- {0x6D790000u, 59u}, // my -> Mymr
- {0xAB0C0000u, 46u}, // myk -> Latn
+ {0xD6CC0000u, 45u}, // mwv -> Latn
+ {0xDACC0000u, 33u}, // mww -> Hmnp
+ {0x8AEC0000u, 45u}, // mxc -> Latn
+ {0xB2EC0000u, 45u}, // mxm -> Latn
+ {0x6D790000u, 58u}, // my -> Mymr
+ {0xAB0C0000u, 45u}, // myk -> Latn
{0xB30C0000u, 21u}, // mym -> Ethi
{0xD70C0000u, 18u}, // myv -> Cyrl
- {0xDB0C0000u, 46u}, // myw -> Latn
- {0xDF0C0000u, 46u}, // myx -> Latn
- {0xE70C0000u, 52u}, // myz -> Mand
- {0xAB2C0000u, 46u}, // mzk -> Latn
- {0xB32C0000u, 46u}, // mzm -> Latn
+ {0xDB0C0000u, 45u}, // myw -> Latn
+ {0xDF0C0000u, 45u}, // myx -> Latn
+ {0xE70C0000u, 51u}, // myz -> Mand
+ {0xAB2C0000u, 45u}, // mzk -> Latn
+ {0xB32C0000u, 45u}, // mzm -> Latn
{0xB72C0000u, 2u}, // mzn -> Arab
- {0xBF2C0000u, 46u}, // mzp -> Latn
- {0xDB2C0000u, 46u}, // mzw -> Latn
- {0xE72C0000u, 46u}, // mzz -> Latn
- {0x6E610000u, 46u}, // na -> Latn
- {0x880D0000u, 46u}, // nac -> Latn
- {0x940D0000u, 46u}, // naf -> Latn
- {0xA80D0000u, 46u}, // nak -> Latn
+ {0xBF2C0000u, 45u}, // mzp -> Latn
+ {0xDB2C0000u, 45u}, // mzw -> Latn
+ {0xE72C0000u, 45u}, // mzz -> Latn
+ {0x6E610000u, 45u}, // na -> Latn
+ {0x880D0000u, 45u}, // nac -> Latn
+ {0x940D0000u, 45u}, // naf -> Latn
+ {0xA80D0000u, 45u}, // nak -> Latn
{0xB40D0000u, 29u}, // nan -> Hans
- {0xBC0D0000u, 46u}, // nap -> Latn
- {0xC00D0000u, 46u}, // naq -> Latn
- {0xC80D0000u, 46u}, // nas -> Latn
- {0x6E620000u, 46u}, // nb -> Latn
- {0x804D0000u, 46u}, // nca -> Latn
- {0x904D0000u, 46u}, // nce -> Latn
- {0x944D0000u, 46u}, // ncf -> Latn
- {0x9C4D0000u, 46u}, // nch -> Latn
- {0xB84D0000u, 46u}, // nco -> Latn
- {0xD04D0000u, 46u}, // ncu -> Latn
- {0x6E640000u, 46u}, // nd -> Latn
- {0x886D0000u, 46u}, // ndc -> Latn
- {0xC86D0000u, 46u}, // nds -> Latn
+ {0xBC0D0000u, 45u}, // nap -> Latn
+ {0xC00D0000u, 45u}, // naq -> Latn
+ {0xC80D0000u, 45u}, // nas -> Latn
+ {0x6E620000u, 45u}, // nb -> Latn
+ {0x804D0000u, 45u}, // nca -> Latn
+ {0x904D0000u, 45u}, // nce -> Latn
+ {0x944D0000u, 45u}, // ncf -> Latn
+ {0x9C4D0000u, 45u}, // nch -> Latn
+ {0xB84D0000u, 45u}, // nco -> Latn
+ {0xD04D0000u, 45u}, // ncu -> Latn
+ {0x6E640000u, 45u}, // nd -> Latn
+ {0x886D0000u, 45u}, // ndc -> Latn
+ {0xC86D0000u, 45u}, // nds -> Latn
{0x6E650000u, 19u}, // ne -> Deva
- {0x848D0000u, 46u}, // neb -> Latn
+ {0x848D0000u, 45u}, // neb -> Latn
{0xD88D0000u, 19u}, // new -> Deva
- {0xDC8D0000u, 46u}, // nex -> Latn
- {0xC4AD0000u, 46u}, // nfr -> Latn
- {0x6E670000u, 46u}, // ng -> Latn
- {0x80CD0000u, 46u}, // nga -> Latn
- {0x84CD0000u, 46u}, // ngb -> Latn
- {0xACCD0000u, 46u}, // ngl -> Latn
- {0x84ED0000u, 46u}, // nhb -> Latn
- {0x90ED0000u, 46u}, // nhe -> Latn
- {0xD8ED0000u, 46u}, // nhw -> Latn
- {0x950D0000u, 46u}, // nif -> Latn
- {0xA10D0000u, 46u}, // nii -> Latn
- {0xA50D0000u, 46u}, // nij -> Latn
- {0xB50D0000u, 46u}, // nin -> Latn
- {0xD10D0000u, 46u}, // niu -> Latn
- {0xE10D0000u, 46u}, // niy -> Latn
- {0xE50D0000u, 46u}, // niz -> Latn
- {0xB92D0000u, 46u}, // njo -> Latn
- {0x994D0000u, 46u}, // nkg -> Latn
- {0xB94D0000u, 46u}, // nko -> Latn
- {0x6E6C0000u, 46u}, // nl -> Latn
- {0x998D0000u, 46u}, // nmg -> Latn
- {0xE58D0000u, 46u}, // nmz -> Latn
- {0x6E6E0000u, 46u}, // nn -> Latn
- {0x95AD0000u, 46u}, // nnf -> Latn
- {0x9DAD0000u, 46u}, // nnh -> Latn
- {0xA9AD0000u, 46u}, // nnk -> Latn
- {0xB1AD0000u, 46u}, // nnm -> Latn
- {0xBDAD0000u, 95u}, // nnp -> Wcho
- {0x6E6F0000u, 46u}, // no -> Latn
- {0x8DCD0000u, 44u}, // nod -> Lana
+ {0xDC8D0000u, 45u}, // nex -> Latn
+ {0xC4AD0000u, 45u}, // nfr -> Latn
+ {0x6E670000u, 45u}, // ng -> Latn
+ {0x80CD0000u, 45u}, // nga -> Latn
+ {0x84CD0000u, 45u}, // ngb -> Latn
+ {0xACCD0000u, 45u}, // ngl -> Latn
+ {0x84ED0000u, 45u}, // nhb -> Latn
+ {0x90ED0000u, 45u}, // nhe -> Latn
+ {0xD8ED0000u, 45u}, // nhw -> Latn
+ {0x950D0000u, 45u}, // nif -> Latn
+ {0xA10D0000u, 45u}, // nii -> Latn
+ {0xA50D0000u, 45u}, // nij -> Latn
+ {0xB50D0000u, 45u}, // nin -> Latn
+ {0xD10D0000u, 45u}, // niu -> Latn
+ {0xE10D0000u, 45u}, // niy -> Latn
+ {0xE50D0000u, 45u}, // niz -> Latn
+ {0xB92D0000u, 45u}, // njo -> Latn
+ {0x994D0000u, 45u}, // nkg -> Latn
+ {0xB94D0000u, 45u}, // nko -> Latn
+ {0x6E6C0000u, 45u}, // nl -> Latn
+ {0x998D0000u, 45u}, // nmg -> Latn
+ {0xE58D0000u, 45u}, // nmz -> Latn
+ {0x6E6E0000u, 45u}, // nn -> Latn
+ {0x95AD0000u, 45u}, // nnf -> Latn
+ {0x9DAD0000u, 45u}, // nnh -> Latn
+ {0xA9AD0000u, 45u}, // nnk -> Latn
+ {0xB1AD0000u, 45u}, // nnm -> Latn
+ {0xBDAD0000u, 98u}, // nnp -> Wcho
+ {0x6E6F0000u, 45u}, // no -> Latn
+ {0x8DCD0000u, 43u}, // nod -> Lana
{0x91CD0000u, 19u}, // noe -> Deva
- {0xB5CD0000u, 73u}, // non -> Runr
- {0xBDCD0000u, 46u}, // nop -> Latn
- {0xD1CD0000u, 46u}, // nou -> Latn
- {0xBA0D0000u, 61u}, // nqo -> Nkoo
- {0x6E720000u, 46u}, // nr -> Latn
- {0x862D0000u, 46u}, // nrb -> Latn
+ {0xB5CD0000u, 74u}, // non -> Runr
+ {0xBDCD0000u, 45u}, // nop -> Latn
+ {0xD1CD0000u, 45u}, // nou -> Latn
+ {0xBA0D0000u, 60u}, // nqo -> Nkoo
+ {0x6E720000u, 45u}, // nr -> Latn
+ {0x862D0000u, 45u}, // nrb -> Latn
{0xAA4D0000u, 11u}, // nsk -> Cans
- {0xB64D0000u, 46u}, // nsn -> Latn
- {0xBA4D0000u, 46u}, // nso -> Latn
- {0xCA4D0000u, 46u}, // nss -> Latn
- {0xB26D0000u, 46u}, // ntm -> Latn
- {0xC66D0000u, 46u}, // ntr -> Latn
- {0xA28D0000u, 46u}, // nui -> Latn
- {0xBE8D0000u, 46u}, // nup -> Latn
- {0xCA8D0000u, 46u}, // nus -> Latn
- {0xD68D0000u, 46u}, // nuv -> Latn
- {0xDE8D0000u, 46u}, // nux -> Latn
- {0x6E760000u, 46u}, // nv -> Latn
- {0x86CD0000u, 46u}, // nwb -> Latn
- {0xC2ED0000u, 46u}, // nxq -> Latn
- {0xC6ED0000u, 46u}, // nxr -> Latn
- {0x6E790000u, 46u}, // ny -> Latn
- {0xB30D0000u, 46u}, // nym -> Latn
- {0xB70D0000u, 46u}, // nyn -> Latn
- {0xA32D0000u, 46u}, // nzi -> Latn
- {0x6F630000u, 46u}, // oc -> Latn
- {0x88CE0000u, 46u}, // ogc -> Latn
- {0xC54E0000u, 46u}, // okr -> Latn
- {0xD54E0000u, 46u}, // okv -> Latn
- {0x6F6D0000u, 46u}, // om -> Latn
- {0x99AE0000u, 46u}, // ong -> Latn
- {0xB5AE0000u, 46u}, // onn -> Latn
- {0xC9AE0000u, 46u}, // ons -> Latn
- {0xB1EE0000u, 46u}, // opm -> Latn
- {0x6F720000u, 66u}, // or -> Orya
- {0xBA2E0000u, 46u}, // oro -> Latn
+ {0xB64D0000u, 45u}, // nsn -> Latn
+ {0xBA4D0000u, 45u}, // nso -> Latn
+ {0xCA4D0000u, 45u}, // nss -> Latn
+ {0xCE4D0000u, 94u}, // nst -> Tnsa
+ {0xB26D0000u, 45u}, // ntm -> Latn
+ {0xC66D0000u, 45u}, // ntr -> Latn
+ {0xA28D0000u, 45u}, // nui -> Latn
+ {0xBE8D0000u, 45u}, // nup -> Latn
+ {0xCA8D0000u, 45u}, // nus -> Latn
+ {0xD68D0000u, 45u}, // nuv -> Latn
+ {0xDE8D0000u, 45u}, // nux -> Latn
+ {0x6E760000u, 45u}, // nv -> Latn
+ {0x86CD0000u, 45u}, // nwb -> Latn
+ {0xC2ED0000u, 45u}, // nxq -> Latn
+ {0xC6ED0000u, 45u}, // nxr -> Latn
+ {0x6E790000u, 45u}, // ny -> Latn
+ {0xB30D0000u, 45u}, // nym -> Latn
+ {0xB70D0000u, 45u}, // nyn -> Latn
+ {0xA32D0000u, 45u}, // nzi -> Latn
+ {0x6F630000u, 45u}, // oc -> Latn
+ {0x88CE0000u, 45u}, // ogc -> Latn
+ {0xC54E0000u, 45u}, // okr -> Latn
+ {0xD54E0000u, 45u}, // okv -> Latn
+ {0x6F6D0000u, 45u}, // om -> Latn
+ {0x99AE0000u, 45u}, // ong -> Latn
+ {0xB5AE0000u, 45u}, // onn -> Latn
+ {0xC9AE0000u, 45u}, // ons -> Latn
+ {0xB1EE0000u, 45u}, // opm -> Latn
+ {0x6F720000u, 65u}, // or -> Orya
+ {0xBA2E0000u, 45u}, // oro -> Latn
{0xD22E0000u, 2u}, // oru -> Arab
{0x6F730000u, 18u}, // os -> Cyrl
- {0x824E0000u, 67u}, // osa -> Osge
+ {0x824E0000u, 66u}, // osa -> Osge
{0x826E0000u, 2u}, // ota -> Arab
- {0xAA6E0000u, 65u}, // otk -> Orkh
- {0xB32E0000u, 46u}, // ozm -> Latn
+ {0xAA6E0000u, 64u}, // otk -> Orkh
+ {0xA28E0000u, 67u}, // oui -> Ougr
+ {0xB32E0000u, 45u}, // ozm -> Latn
{0x70610000u, 28u}, // pa -> Guru
{0x7061504Bu, 2u}, // pa-PK -> Arab
- {0x980F0000u, 46u}, // pag -> Latn
+ {0x980F0000u, 45u}, // pag -> Latn
{0xAC0F0000u, 69u}, // pal -> Phli
- {0xB00F0000u, 46u}, // pam -> Latn
- {0xBC0F0000u, 46u}, // pap -> Latn
- {0xD00F0000u, 46u}, // pau -> Latn
- {0xA02F0000u, 46u}, // pbi -> Latn
- {0x8C4F0000u, 46u}, // pcd -> Latn
- {0xB04F0000u, 46u}, // pcm -> Latn
- {0x886F0000u, 46u}, // pdc -> Latn
- {0xCC6F0000u, 46u}, // pdt -> Latn
- {0x8C8F0000u, 46u}, // ped -> Latn
- {0xB88F0000u, 96u}, // peo -> Xpeo
- {0xDC8F0000u, 46u}, // pex -> Latn
- {0xACAF0000u, 46u}, // pfl -> Latn
+ {0xB00F0000u, 45u}, // pam -> Latn
+ {0xBC0F0000u, 45u}, // pap -> Latn
+ {0xD00F0000u, 45u}, // pau -> Latn
+ {0xA02F0000u, 45u}, // pbi -> Latn
+ {0x8C4F0000u, 45u}, // pcd -> Latn
+ {0xB04F0000u, 45u}, // pcm -> Latn
+ {0x886F0000u, 45u}, // pdc -> Latn
+ {0xCC6F0000u, 45u}, // pdt -> Latn
+ {0x8C8F0000u, 45u}, // ped -> Latn
+ {0xB88F0000u, 99u}, // peo -> Xpeo
+ {0xDC8F0000u, 45u}, // pex -> Latn
+ {0xACAF0000u, 45u}, // pfl -> Latn
{0xACEF0000u, 2u}, // phl -> Arab
{0xB4EF0000u, 70u}, // phn -> Phnx
- {0xAD0F0000u, 46u}, // pil -> Latn
- {0xBD0F0000u, 46u}, // pip -> Latn
+ {0xAD0F0000u, 45u}, // pil -> Latn
+ {0xBD0F0000u, 45u}, // pip -> Latn
{0x814F0000u, 9u}, // pka -> Brah
- {0xB94F0000u, 46u}, // pko -> Latn
- {0x706C0000u, 46u}, // pl -> Latn
- {0x816F0000u, 46u}, // pla -> Latn
- {0xC98F0000u, 46u}, // pms -> Latn
- {0x99AF0000u, 46u}, // png -> Latn
- {0xB5AF0000u, 46u}, // pnn -> Latn
+ {0xB94F0000u, 45u}, // pko -> Latn
+ {0x706C0000u, 45u}, // pl -> Latn
+ {0x816F0000u, 45u}, // pla -> Latn
+ {0xC98F0000u, 45u}, // pms -> Latn
+ {0x99AF0000u, 45u}, // png -> Latn
+ {0xB5AF0000u, 45u}, // pnn -> Latn
{0xCDAF0000u, 26u}, // pnt -> Grek
- {0xB5CF0000u, 46u}, // pon -> Latn
+ {0xB5CF0000u, 45u}, // pon -> Latn
{0x81EF0000u, 19u}, // ppa -> Deva
- {0xB9EF0000u, 46u}, // ppo -> Latn
- {0x822F0000u, 39u}, // pra -> Khar
+ {0xB9EF0000u, 45u}, // ppo -> Latn
+ {0x822F0000u, 38u}, // pra -> Khar
{0x8E2F0000u, 2u}, // prd -> Arab
- {0x9A2F0000u, 46u}, // prg -> Latn
+ {0x9A2F0000u, 45u}, // prg -> Latn
{0x70730000u, 2u}, // ps -> Arab
- {0xCA4F0000u, 46u}, // pss -> Latn
- {0x70740000u, 46u}, // pt -> Latn
- {0xBE6F0000u, 46u}, // ptp -> Latn
- {0xD28F0000u, 46u}, // puu -> Latn
- {0x82CF0000u, 46u}, // pwa -> Latn
- {0x71750000u, 46u}, // qu -> Latn
- {0x8A900000u, 46u}, // quc -> Latn
- {0x9A900000u, 46u}, // qug -> Latn
- {0xA0110000u, 46u}, // rai -> Latn
+ {0xCA4F0000u, 45u}, // pss -> Latn
+ {0x70740000u, 45u}, // pt -> Latn
+ {0xBE6F0000u, 45u}, // ptp -> Latn
+ {0xD28F0000u, 45u}, // puu -> Latn
+ {0x82CF0000u, 45u}, // pwa -> Latn
+ {0x71750000u, 45u}, // qu -> Latn
+ {0x8A900000u, 45u}, // quc -> Latn
+ {0x9A900000u, 45u}, // qug -> Latn
+ {0xA0110000u, 45u}, // rai -> Latn
{0xA4110000u, 19u}, // raj -> Deva
- {0xB8110000u, 46u}, // rao -> Latn
- {0x94510000u, 46u}, // rcf -> Latn
- {0xA4910000u, 46u}, // rej -> Latn
- {0xAC910000u, 46u}, // rel -> Latn
- {0xC8910000u, 46u}, // res -> Latn
- {0xB4D10000u, 46u}, // rgn -> Latn
- {0x98F10000u, 2u}, // rhg -> Arab
- {0x81110000u, 46u}, // ria -> Latn
- {0x95110000u, 89u}, // rif -> Tfng
- {0x95114E4Cu, 46u}, // rif-NL -> Latn
+ {0xB8110000u, 45u}, // rao -> Latn
+ {0x94510000u, 45u}, // rcf -> Latn
+ {0xA4910000u, 45u}, // rej -> Latn
+ {0xAC910000u, 45u}, // rel -> Latn
+ {0xC8910000u, 45u}, // res -> Latn
+ {0xB4D10000u, 45u}, // rgn -> Latn
+ {0x98F10000u, 73u}, // rhg -> Rohg
+ {0x81110000u, 45u}, // ria -> Latn
+ {0x95110000u, 90u}, // rif -> Tfng
+ {0x95114E4Cu, 45u}, // rif-NL -> Latn
{0xC9310000u, 19u}, // rjs -> Deva
{0xCD510000u, 8u}, // rkt -> Beng
- {0x726D0000u, 46u}, // rm -> Latn
- {0x95910000u, 46u}, // rmf -> Latn
- {0xB9910000u, 46u}, // rmo -> Latn
+ {0x726D0000u, 45u}, // rm -> Latn
+ {0x95910000u, 45u}, // rmf -> Latn
+ {0xB9910000u, 45u}, // rmo -> Latn
{0xCD910000u, 2u}, // rmt -> Arab
- {0xD1910000u, 46u}, // rmu -> Latn
- {0x726E0000u, 46u}, // rn -> Latn
- {0x81B10000u, 46u}, // rna -> Latn
- {0x99B10000u, 46u}, // rng -> Latn
- {0x726F0000u, 46u}, // ro -> Latn
- {0x85D10000u, 46u}, // rob -> Latn
- {0x95D10000u, 46u}, // rof -> Latn
- {0xB9D10000u, 46u}, // roo -> Latn
- {0xBA310000u, 46u}, // rro -> Latn
- {0xB2710000u, 46u}, // rtm -> Latn
+ {0xD1910000u, 45u}, // rmu -> Latn
+ {0x726E0000u, 45u}, // rn -> Latn
+ {0x81B10000u, 45u}, // rna -> Latn
+ {0x99B10000u, 45u}, // rng -> Latn
+ {0x726F0000u, 45u}, // ro -> Latn
+ {0x85D10000u, 45u}, // rob -> Latn
+ {0x95D10000u, 45u}, // rof -> Latn
+ {0xB9D10000u, 45u}, // roo -> Latn
+ {0xBA310000u, 45u}, // rro -> Latn
+ {0xB2710000u, 45u}, // rtm -> Latn
{0x72750000u, 18u}, // ru -> Cyrl
{0x92910000u, 18u}, // rue -> Cyrl
- {0x9A910000u, 46u}, // rug -> Latn
- {0x72770000u, 46u}, // rw -> Latn
- {0xAAD10000u, 46u}, // rwk -> Latn
- {0xBAD10000u, 46u}, // rwo -> Latn
- {0xD3110000u, 38u}, // ryu -> Kana
+ {0x9A910000u, 45u}, // rug -> Latn
+ {0x72770000u, 45u}, // rw -> Latn
+ {0xAAD10000u, 45u}, // rwk -> Latn
+ {0xBAD10000u, 45u}, // rwo -> Latn
+ {0xD3110000u, 37u}, // ryu -> Kana
{0x73610000u, 19u}, // sa -> Deva
- {0x94120000u, 46u}, // saf -> Latn
+ {0x94120000u, 45u}, // saf -> Latn
{0x9C120000u, 18u}, // sah -> Cyrl
- {0xC0120000u, 46u}, // saq -> Latn
- {0xC8120000u, 46u}, // sas -> Latn
- {0xCC120000u, 64u}, // sat -> Olck
- {0xD4120000u, 46u}, // sav -> Latn
- {0xE4120000u, 76u}, // saz -> Saur
- {0x80320000u, 46u}, // sba -> Latn
- {0x90320000u, 46u}, // sbe -> Latn
- {0xBC320000u, 46u}, // sbp -> Latn
- {0x73630000u, 46u}, // sc -> Latn
+ {0xC0120000u, 45u}, // saq -> Latn
+ {0xC8120000u, 45u}, // sas -> Latn
+ {0xCC120000u, 63u}, // sat -> Olck
+ {0xD4120000u, 45u}, // sav -> Latn
+ {0xE4120000u, 77u}, // saz -> Saur
+ {0x80320000u, 45u}, // sba -> Latn
+ {0x90320000u, 45u}, // sbe -> Latn
+ {0xBC320000u, 45u}, // sbp -> Latn
+ {0x73630000u, 45u}, // sc -> Latn
{0xA8520000u, 19u}, // sck -> Deva
{0xAC520000u, 2u}, // scl -> Arab
- {0xB4520000u, 46u}, // scn -> Latn
- {0xB8520000u, 46u}, // sco -> Latn
- {0xC8520000u, 46u}, // scs -> Latn
+ {0xB4520000u, 45u}, // scn -> Latn
+ {0xB8520000u, 45u}, // sco -> Latn
+ {0xC8520000u, 45u}, // scs -> Latn
{0x73640000u, 2u}, // sd -> Arab
- {0x88720000u, 46u}, // sdc -> Latn
+ {0x88720000u, 45u}, // sdc -> Latn
{0x9C720000u, 2u}, // sdh -> Arab
- {0x73650000u, 46u}, // se -> Latn
- {0x94920000u, 46u}, // sef -> Latn
- {0x9C920000u, 46u}, // seh -> Latn
- {0xA0920000u, 46u}, // sei -> Latn
- {0xC8920000u, 46u}, // ses -> Latn
- {0x73670000u, 46u}, // sg -> Latn
- {0x80D20000u, 63u}, // sga -> Ogam
- {0xC8D20000u, 46u}, // sgs -> Latn
+ {0x73650000u, 45u}, // se -> Latn
+ {0x94920000u, 45u}, // sef -> Latn
+ {0x9C920000u, 45u}, // seh -> Latn
+ {0xA0920000u, 45u}, // sei -> Latn
+ {0xC8920000u, 45u}, // ses -> Latn
+ {0x73670000u, 45u}, // sg -> Latn
+ {0x80D20000u, 62u}, // sga -> Ogam
+ {0xC8D20000u, 45u}, // sgs -> Latn
{0xD8D20000u, 21u}, // sgw -> Ethi
- {0xE4D20000u, 46u}, // sgz -> Latn
- {0x73680000u, 46u}, // sh -> Latn
- {0xA0F20000u, 89u}, // shi -> Tfng
- {0xA8F20000u, 46u}, // shk -> Latn
- {0xB4F20000u, 59u}, // shn -> Mymr
+ {0xE4D20000u, 45u}, // sgz -> Latn
+ {0x73680000u, 45u}, // sh -> Latn
+ {0xA0F20000u, 90u}, // shi -> Tfng
+ {0xA8F20000u, 45u}, // shk -> Latn
+ {0xB4F20000u, 58u}, // shn -> Mymr
{0xD0F20000u, 2u}, // shu -> Arab
- {0x73690000u, 78u}, // si -> Sinh
- {0x8D120000u, 46u}, // sid -> Latn
- {0x99120000u, 46u}, // sig -> Latn
- {0xAD120000u, 46u}, // sil -> Latn
- {0xB1120000u, 46u}, // sim -> Latn
- {0xC5320000u, 46u}, // sjr -> Latn
- {0x736B0000u, 46u}, // sk -> Latn
- {0x89520000u, 46u}, // skc -> Latn
+ {0x73690000u, 79u}, // si -> Sinh
+ {0x8D120000u, 45u}, // sid -> Latn
+ {0x99120000u, 45u}, // sig -> Latn
+ {0xAD120000u, 45u}, // sil -> Latn
+ {0xB1120000u, 45u}, // sim -> Latn
+ {0xC5320000u, 45u}, // sjr -> Latn
+ {0x736B0000u, 45u}, // sk -> Latn
+ {0x89520000u, 45u}, // skc -> Latn
{0xC5520000u, 2u}, // skr -> Arab
- {0xC9520000u, 46u}, // sks -> Latn
- {0x736C0000u, 46u}, // sl -> Latn
- {0x8D720000u, 46u}, // sld -> Latn
- {0xA1720000u, 46u}, // sli -> Latn
- {0xAD720000u, 46u}, // sll -> Latn
- {0xE1720000u, 46u}, // sly -> Latn
- {0x736D0000u, 46u}, // sm -> Latn
- {0x81920000u, 46u}, // sma -> Latn
- {0xA5920000u, 46u}, // smj -> Latn
- {0xB5920000u, 46u}, // smn -> Latn
- {0xBD920000u, 74u}, // smp -> Samr
- {0xC1920000u, 46u}, // smq -> Latn
- {0xC9920000u, 46u}, // sms -> Latn
- {0x736E0000u, 46u}, // sn -> Latn
- {0x89B20000u, 46u}, // snc -> Latn
- {0xA9B20000u, 46u}, // snk -> Latn
- {0xBDB20000u, 46u}, // snp -> Latn
- {0xDDB20000u, 46u}, // snx -> Latn
- {0xE1B20000u, 46u}, // sny -> Latn
- {0x736F0000u, 46u}, // so -> Latn
- {0x99D20000u, 79u}, // sog -> Sogd
- {0xA9D20000u, 46u}, // sok -> Latn
- {0xC1D20000u, 46u}, // soq -> Latn
- {0xD1D20000u, 91u}, // sou -> Thai
- {0xE1D20000u, 46u}, // soy -> Latn
- {0x8DF20000u, 46u}, // spd -> Latn
- {0xADF20000u, 46u}, // spl -> Latn
- {0xC9F20000u, 46u}, // sps -> Latn
- {0x73710000u, 46u}, // sq -> Latn
+ {0xC9520000u, 45u}, // sks -> Latn
+ {0x736C0000u, 45u}, // sl -> Latn
+ {0x8D720000u, 45u}, // sld -> Latn
+ {0xA1720000u, 45u}, // sli -> Latn
+ {0xAD720000u, 45u}, // sll -> Latn
+ {0xE1720000u, 45u}, // sly -> Latn
+ {0x736D0000u, 45u}, // sm -> Latn
+ {0x81920000u, 45u}, // sma -> Latn
+ {0xA5920000u, 45u}, // smj -> Latn
+ {0xB5920000u, 45u}, // smn -> Latn
+ {0xBD920000u, 75u}, // smp -> Samr
+ {0xC1920000u, 45u}, // smq -> Latn
+ {0xC9920000u, 45u}, // sms -> Latn
+ {0x736E0000u, 45u}, // sn -> Latn
+ {0x89B20000u, 45u}, // snc -> Latn
+ {0xA9B20000u, 45u}, // snk -> Latn
+ {0xBDB20000u, 45u}, // snp -> Latn
+ {0xDDB20000u, 45u}, // snx -> Latn
+ {0xE1B20000u, 45u}, // sny -> Latn
+ {0x736F0000u, 45u}, // so -> Latn
+ {0x99D20000u, 80u}, // sog -> Sogd
+ {0xA9D20000u, 45u}, // sok -> Latn
+ {0xC1D20000u, 45u}, // soq -> Latn
+ {0xD1D20000u, 92u}, // sou -> Thai
+ {0xE1D20000u, 45u}, // soy -> Latn
+ {0x8DF20000u, 45u}, // spd -> Latn
+ {0xADF20000u, 45u}, // spl -> Latn
+ {0xC9F20000u, 45u}, // sps -> Latn
+ {0x73710000u, 45u}, // sq -> Latn
{0x73720000u, 18u}, // sr -> Cyrl
- {0x73724D45u, 46u}, // sr-ME -> Latn
- {0x7372524Fu, 46u}, // sr-RO -> Latn
- {0x73725255u, 46u}, // sr-RU -> Latn
- {0x73725452u, 46u}, // sr-TR -> Latn
- {0x86320000u, 80u}, // srb -> Sora
- {0xB6320000u, 46u}, // srn -> Latn
- {0xC6320000u, 46u}, // srr -> Latn
+ {0x73724D45u, 45u}, // sr-ME -> Latn
+ {0x7372524Fu, 45u}, // sr-RO -> Latn
+ {0x73725255u, 45u}, // sr-RU -> Latn
+ {0x73725452u, 45u}, // sr-TR -> Latn
+ {0x86320000u, 81u}, // srb -> Sora
+ {0xB6320000u, 45u}, // srn -> Latn
+ {0xC6320000u, 45u}, // srr -> Latn
{0xDE320000u, 19u}, // srx -> Deva
- {0x73730000u, 46u}, // ss -> Latn
- {0x8E520000u, 46u}, // ssd -> Latn
- {0x9A520000u, 46u}, // ssg -> Latn
- {0xE2520000u, 46u}, // ssy -> Latn
- {0x73740000u, 46u}, // st -> Latn
- {0xAA720000u, 46u}, // stk -> Latn
- {0xC2720000u, 46u}, // stq -> Latn
- {0x73750000u, 46u}, // su -> Latn
- {0x82920000u, 46u}, // sua -> Latn
- {0x92920000u, 46u}, // sue -> Latn
- {0xAA920000u, 46u}, // suk -> Latn
- {0xC6920000u, 46u}, // sur -> Latn
- {0xCA920000u, 46u}, // sus -> Latn
- {0x73760000u, 46u}, // sv -> Latn
- {0x73770000u, 46u}, // sw -> Latn
+ {0x73730000u, 45u}, // ss -> Latn
+ {0x8E520000u, 45u}, // ssd -> Latn
+ {0x9A520000u, 45u}, // ssg -> Latn
+ {0xE2520000u, 45u}, // ssy -> Latn
+ {0x73740000u, 45u}, // st -> Latn
+ {0xAA720000u, 45u}, // stk -> Latn
+ {0xC2720000u, 45u}, // stq -> Latn
+ {0x73750000u, 45u}, // su -> Latn
+ {0x82920000u, 45u}, // sua -> Latn
+ {0x92920000u, 45u}, // sue -> Latn
+ {0xAA920000u, 45u}, // suk -> Latn
+ {0xC6920000u, 45u}, // sur -> Latn
+ {0xCA920000u, 45u}, // sus -> Latn
+ {0x73760000u, 45u}, // sv -> Latn
+ {0x73770000u, 45u}, // sw -> Latn
{0x86D20000u, 2u}, // swb -> Arab
- {0x8AD20000u, 46u}, // swc -> Latn
- {0x9AD20000u, 46u}, // swg -> Latn
- {0xBED20000u, 46u}, // swp -> Latn
+ {0x8AD20000u, 45u}, // swc -> Latn
+ {0x9AD20000u, 45u}, // swg -> Latn
+ {0xBED20000u, 45u}, // swp -> Latn
{0xD6D20000u, 19u}, // swv -> Deva
- {0xB6F20000u, 46u}, // sxn -> Latn
- {0xDAF20000u, 46u}, // sxw -> Latn
+ {0xB6F20000u, 45u}, // sxn -> Latn
+ {0xDAF20000u, 45u}, // sxw -> Latn
{0xAF120000u, 8u}, // syl -> Beng
- {0xC7120000u, 82u}, // syr -> Syrc
- {0xAF320000u, 46u}, // szl -> Latn
- {0x74610000u, 85u}, // ta -> Taml
+ {0xC7120000u, 83u}, // syr -> Syrc
+ {0xAF320000u, 45u}, // szl -> Latn
+ {0x74610000u, 86u}, // ta -> Taml
{0xA4130000u, 19u}, // taj -> Deva
- {0xAC130000u, 46u}, // tal -> Latn
- {0xB4130000u, 46u}, // tan -> Latn
- {0xC0130000u, 46u}, // taq -> Latn
- {0x88330000u, 46u}, // tbc -> Latn
- {0x8C330000u, 46u}, // tbd -> Latn
- {0x94330000u, 46u}, // tbf -> Latn
- {0x98330000u, 46u}, // tbg -> Latn
- {0xB8330000u, 46u}, // tbo -> Latn
- {0xD8330000u, 46u}, // tbw -> Latn
- {0xE4330000u, 46u}, // tbz -> Latn
- {0xA0530000u, 46u}, // tci -> Latn
- {0xE0530000u, 42u}, // tcy -> Knda
- {0x8C730000u, 83u}, // tdd -> Tale
+ {0xAC130000u, 45u}, // tal -> Latn
+ {0xB4130000u, 45u}, // tan -> Latn
+ {0xC0130000u, 45u}, // taq -> Latn
+ {0x88330000u, 45u}, // tbc -> Latn
+ {0x8C330000u, 45u}, // tbd -> Latn
+ {0x94330000u, 45u}, // tbf -> Latn
+ {0x98330000u, 45u}, // tbg -> Latn
+ {0xB8330000u, 45u}, // tbo -> Latn
+ {0xD8330000u, 45u}, // tbw -> Latn
+ {0xE4330000u, 45u}, // tbz -> Latn
+ {0xA0530000u, 45u}, // tci -> Latn
+ {0xE0530000u, 41u}, // tcy -> Knda
+ {0x8C730000u, 84u}, // tdd -> Tale
{0x98730000u, 19u}, // tdg -> Deva
{0x9C730000u, 19u}, // tdh -> Deva
- {0xD0730000u, 46u}, // tdu -> Latn
- {0x74650000u, 88u}, // te -> Telu
- {0x8C930000u, 46u}, // ted -> Latn
- {0xB0930000u, 46u}, // tem -> Latn
- {0xB8930000u, 46u}, // teo -> Latn
- {0xCC930000u, 46u}, // tet -> Latn
- {0xA0B30000u, 46u}, // tfi -> Latn
+ {0xD0730000u, 45u}, // tdu -> Latn
+ {0x74650000u, 89u}, // te -> Telu
+ {0x8C930000u, 45u}, // ted -> Latn
+ {0xB0930000u, 45u}, // tem -> Latn
+ {0xB8930000u, 45u}, // teo -> Latn
+ {0xCC930000u, 45u}, // tet -> Latn
+ {0xA0B30000u, 45u}, // tfi -> Latn
{0x74670000u, 18u}, // tg -> Cyrl
{0x7467504Bu, 2u}, // tg-PK -> Arab
- {0x88D30000u, 46u}, // tgc -> Latn
- {0xB8D30000u, 46u}, // tgo -> Latn
- {0xD0D30000u, 46u}, // tgu -> Latn
- {0x74680000u, 91u}, // th -> Thai
+ {0x88D30000u, 45u}, // tgc -> Latn
+ {0xB8D30000u, 45u}, // tgo -> Latn
+ {0xD0D30000u, 45u}, // tgu -> Latn
+ {0x74680000u, 92u}, // th -> Thai
{0xACF30000u, 19u}, // thl -> Deva
{0xC0F30000u, 19u}, // thq -> Deva
{0xC4F30000u, 19u}, // thr -> Deva
{0x74690000u, 21u}, // ti -> Ethi
- {0x95130000u, 46u}, // tif -> Latn
+ {0x95130000u, 45u}, // tif -> Latn
{0x99130000u, 21u}, // tig -> Ethi
- {0xA9130000u, 46u}, // tik -> Latn
- {0xB1130000u, 46u}, // tim -> Latn
- {0xB9130000u, 46u}, // tio -> Latn
- {0xD5130000u, 46u}, // tiv -> Latn
- {0x746B0000u, 46u}, // tk -> Latn
- {0xAD530000u, 46u}, // tkl -> Latn
- {0xC5530000u, 46u}, // tkr -> Latn
+ {0xA9130000u, 45u}, // tik -> Latn
+ {0xB1130000u, 45u}, // tim -> Latn
+ {0xB9130000u, 45u}, // tio -> Latn
+ {0xD5130000u, 45u}, // tiv -> Latn
+ {0x746B0000u, 45u}, // tk -> Latn
+ {0xAD530000u, 45u}, // tkl -> Latn
+ {0xC5530000u, 45u}, // tkr -> Latn
{0xCD530000u, 19u}, // tkt -> Deva
- {0x746C0000u, 46u}, // tl -> Latn
- {0x95730000u, 46u}, // tlf -> Latn
- {0xDD730000u, 46u}, // tlx -> Latn
- {0xE1730000u, 46u}, // tly -> Latn
- {0x9D930000u, 46u}, // tmh -> Latn
- {0xE1930000u, 46u}, // tmy -> Latn
- {0x746E0000u, 46u}, // tn -> Latn
- {0x9DB30000u, 46u}, // tnh -> Latn
- {0x746F0000u, 46u}, // to -> Latn
- {0x95D30000u, 46u}, // tof -> Latn
- {0x99D30000u, 46u}, // tog -> Latn
- {0xC1D30000u, 46u}, // toq -> Latn
- {0xA1F30000u, 46u}, // tpi -> Latn
- {0xB1F30000u, 46u}, // tpm -> Latn
- {0xE5F30000u, 46u}, // tpz -> Latn
- {0xBA130000u, 46u}, // tqo -> Latn
- {0x74720000u, 46u}, // tr -> Latn
- {0xD2330000u, 46u}, // tru -> Latn
- {0xD6330000u, 46u}, // trv -> Latn
+ {0x746C0000u, 45u}, // tl -> Latn
+ {0x95730000u, 45u}, // tlf -> Latn
+ {0xDD730000u, 45u}, // tlx -> Latn
+ {0xE1730000u, 45u}, // tly -> Latn
+ {0x9D930000u, 45u}, // tmh -> Latn
+ {0xE1930000u, 45u}, // tmy -> Latn
+ {0x746E0000u, 45u}, // tn -> Latn
+ {0x9DB30000u, 45u}, // tnh -> Latn
+ {0x746F0000u, 45u}, // to -> Latn
+ {0x95D30000u, 45u}, // tof -> Latn
+ {0x99D30000u, 45u}, // tog -> Latn
+ {0xC1D30000u, 45u}, // toq -> Latn
+ {0xA1F30000u, 45u}, // tpi -> Latn
+ {0xB1F30000u, 45u}, // tpm -> Latn
+ {0xE5F30000u, 45u}, // tpz -> Latn
+ {0xBA130000u, 45u}, // tqo -> Latn
+ {0x74720000u, 45u}, // tr -> Latn
+ {0xD2330000u, 45u}, // tru -> Latn
+ {0xD6330000u, 45u}, // trv -> Latn
{0xDA330000u, 2u}, // trw -> Arab
- {0x74730000u, 46u}, // ts -> Latn
+ {0x74730000u, 45u}, // ts -> Latn
{0x8E530000u, 26u}, // tsd -> Grek
{0x96530000u, 19u}, // tsf -> Deva
- {0x9A530000u, 46u}, // tsg -> Latn
- {0xA6530000u, 92u}, // tsj -> Tibt
- {0xDA530000u, 46u}, // tsw -> Latn
+ {0x9A530000u, 45u}, // tsg -> Latn
+ {0xA6530000u, 93u}, // tsj -> Tibt
+ {0xDA530000u, 45u}, // tsw -> Latn
{0x74740000u, 18u}, // tt -> Cyrl
- {0x8E730000u, 46u}, // ttd -> Latn
- {0x92730000u, 46u}, // tte -> Latn
- {0xA6730000u, 46u}, // ttj -> Latn
- {0xC6730000u, 46u}, // ttr -> Latn
- {0xCA730000u, 91u}, // tts -> Thai
- {0xCE730000u, 46u}, // ttt -> Latn
- {0x9E930000u, 46u}, // tuh -> Latn
- {0xAE930000u, 46u}, // tul -> Latn
- {0xB2930000u, 46u}, // tum -> Latn
- {0xC2930000u, 46u}, // tuq -> Latn
- {0x8EB30000u, 46u}, // tvd -> Latn
- {0xAEB30000u, 46u}, // tvl -> Latn
- {0xD2B30000u, 46u}, // tvu -> Latn
- {0x9ED30000u, 46u}, // twh -> Latn
- {0xC2D30000u, 46u}, // twq -> Latn
- {0x9AF30000u, 86u}, // txg -> Tang
- {0x74790000u, 46u}, // ty -> Latn
- {0x83130000u, 46u}, // tya -> Latn
+ {0x8E730000u, 45u}, // ttd -> Latn
+ {0x92730000u, 45u}, // tte -> Latn
+ {0xA6730000u, 45u}, // ttj -> Latn
+ {0xC6730000u, 45u}, // ttr -> Latn
+ {0xCA730000u, 92u}, // tts -> Thai
+ {0xCE730000u, 45u}, // ttt -> Latn
+ {0x9E930000u, 45u}, // tuh -> Latn
+ {0xAE930000u, 45u}, // tul -> Latn
+ {0xB2930000u, 45u}, // tum -> Latn
+ {0xC2930000u, 45u}, // tuq -> Latn
+ {0x8EB30000u, 45u}, // tvd -> Latn
+ {0xAEB30000u, 45u}, // tvl -> Latn
+ {0xD2B30000u, 45u}, // tvu -> Latn
+ {0x9ED30000u, 45u}, // twh -> Latn
+ {0xC2D30000u, 45u}, // twq -> Latn
+ {0x9AF30000u, 87u}, // txg -> Tang
+ {0xBAF30000u, 95u}, // txo -> Toto
+ {0x74790000u, 45u}, // ty -> Latn
+ {0x83130000u, 45u}, // tya -> Latn
{0xD7130000u, 18u}, // tyv -> Cyrl
- {0xB3330000u, 46u}, // tzm -> Latn
- {0xD0340000u, 46u}, // ubu -> Latn
+ {0xB3330000u, 45u}, // tzm -> Latn
+ {0xD0340000u, 45u}, // ubu -> Latn
{0xA0740000u, 0u}, // udi -> Aghb
{0xB0740000u, 18u}, // udm -> Cyrl
{0x75670000u, 2u}, // ug -> Arab
{0x75674B5Au, 18u}, // ug-KZ -> Cyrl
{0x75674D4Eu, 18u}, // ug-MN -> Cyrl
- {0x80D40000u, 93u}, // uga -> Ugar
+ {0x80D40000u, 96u}, // uga -> Ugar
{0x756B0000u, 18u}, // uk -> Cyrl
- {0xA1740000u, 46u}, // uli -> Latn
- {0x85940000u, 46u}, // umb -> Latn
+ {0xA1740000u, 45u}, // uli -> Latn
+ {0x85940000u, 45u}, // umb -> Latn
{0xC5B40000u, 8u}, // unr -> Beng
{0xC5B44E50u, 19u}, // unr-NP -> Deva
{0xDDB40000u, 8u}, // unx -> Beng
- {0xA9D40000u, 46u}, // uok -> Latn
+ {0xA9D40000u, 45u}, // uok -> Latn
{0x75720000u, 2u}, // ur -> Arab
- {0xA2340000u, 46u}, // uri -> Latn
- {0xCE340000u, 46u}, // urt -> Latn
- {0xDA340000u, 46u}, // urw -> Latn
- {0x82540000u, 46u}, // usa -> Latn
- {0x9E740000u, 46u}, // uth -> Latn
- {0xC6740000u, 46u}, // utr -> Latn
- {0x9EB40000u, 46u}, // uvh -> Latn
- {0xAEB40000u, 46u}, // uvl -> Latn
- {0x757A0000u, 46u}, // uz -> Latn
+ {0xA2340000u, 45u}, // uri -> Latn
+ {0xCE340000u, 45u}, // urt -> Latn
+ {0xDA340000u, 45u}, // urw -> Latn
+ {0x82540000u, 45u}, // usa -> Latn
+ {0x9E740000u, 45u}, // uth -> Latn
+ {0xC6740000u, 45u}, // utr -> Latn
+ {0x9EB40000u, 45u}, // uvh -> Latn
+ {0xAEB40000u, 45u}, // uvl -> Latn
+ {0x757A0000u, 45u}, // uz -> Latn
{0x757A4146u, 2u}, // uz-AF -> Arab
{0x757A434Eu, 18u}, // uz-CN -> Cyrl
- {0x98150000u, 46u}, // vag -> Latn
- {0xA0150000u, 94u}, // vai -> Vaii
- {0xB4150000u, 46u}, // van -> Latn
- {0x76650000u, 46u}, // ve -> Latn
- {0x88950000u, 46u}, // vec -> Latn
- {0xBC950000u, 46u}, // vep -> Latn
- {0x76690000u, 46u}, // vi -> Latn
- {0x89150000u, 46u}, // vic -> Latn
- {0xD5150000u, 46u}, // viv -> Latn
- {0xC9750000u, 46u}, // vls -> Latn
- {0x95950000u, 46u}, // vmf -> Latn
- {0xD9950000u, 46u}, // vmw -> Latn
- {0x766F0000u, 46u}, // vo -> Latn
- {0xCDD50000u, 46u}, // vot -> Latn
- {0xBA350000u, 46u}, // vro -> Latn
- {0xB6950000u, 46u}, // vun -> Latn
- {0xCE950000u, 46u}, // vut -> Latn
- {0x77610000u, 46u}, // wa -> Latn
- {0x90160000u, 46u}, // wae -> Latn
- {0xA4160000u, 46u}, // waj -> Latn
+ {0x98150000u, 45u}, // vag -> Latn
+ {0xA0150000u, 97u}, // vai -> Vaii
+ {0xB4150000u, 45u}, // van -> Latn
+ {0x76650000u, 45u}, // ve -> Latn
+ {0x88950000u, 45u}, // vec -> Latn
+ {0xBC950000u, 45u}, // vep -> Latn
+ {0x76690000u, 45u}, // vi -> Latn
+ {0x89150000u, 45u}, // vic -> Latn
+ {0xD5150000u, 45u}, // viv -> Latn
+ {0xC9750000u, 45u}, // vls -> Latn
+ {0x95950000u, 45u}, // vmf -> Latn
+ {0xD9950000u, 45u}, // vmw -> Latn
+ {0x766F0000u, 45u}, // vo -> Latn
+ {0xCDD50000u, 45u}, // vot -> Latn
+ {0xBA350000u, 45u}, // vro -> Latn
+ {0xB6950000u, 45u}, // vun -> Latn
+ {0xCE950000u, 45u}, // vut -> Latn
+ {0x77610000u, 45u}, // wa -> Latn
+ {0x90160000u, 45u}, // wae -> Latn
+ {0xA4160000u, 45u}, // waj -> Latn
{0xAC160000u, 21u}, // wal -> Ethi
- {0xB4160000u, 46u}, // wan -> Latn
- {0xC4160000u, 46u}, // war -> Latn
- {0xBC360000u, 46u}, // wbp -> Latn
- {0xC0360000u, 88u}, // wbq -> Telu
+ {0xB4160000u, 45u}, // wan -> Latn
+ {0xC4160000u, 45u}, // war -> Latn
+ {0xBC360000u, 45u}, // wbp -> Latn
+ {0xC0360000u, 89u}, // wbq -> Telu
{0xC4360000u, 19u}, // wbr -> Deva
- {0xA0560000u, 46u}, // wci -> Latn
- {0xC4960000u, 46u}, // wer -> Latn
- {0xA0D60000u, 46u}, // wgi -> Latn
- {0x98F60000u, 46u}, // whg -> Latn
- {0x85160000u, 46u}, // wib -> Latn
- {0xD1160000u, 46u}, // wiu -> Latn
- {0xD5160000u, 46u}, // wiv -> Latn
- {0x81360000u, 46u}, // wja -> Latn
- {0xA1360000u, 46u}, // wji -> Latn
- {0xC9760000u, 46u}, // wls -> Latn
- {0xB9960000u, 46u}, // wmo -> Latn
- {0x89B60000u, 46u}, // wnc -> Latn
+ {0xA0560000u, 45u}, // wci -> Latn
+ {0xC4960000u, 45u}, // wer -> Latn
+ {0xA0D60000u, 45u}, // wgi -> Latn
+ {0x98F60000u, 45u}, // whg -> Latn
+ {0x85160000u, 45u}, // wib -> Latn
+ {0xD1160000u, 45u}, // wiu -> Latn
+ {0xD5160000u, 45u}, // wiv -> Latn
+ {0x81360000u, 45u}, // wja -> Latn
+ {0xA1360000u, 45u}, // wji -> Latn
+ {0xC9760000u, 45u}, // wls -> Latn
+ {0xB9960000u, 45u}, // wmo -> Latn
+ {0x89B60000u, 45u}, // wnc -> Latn
{0xA1B60000u, 2u}, // wni -> Arab
- {0xD1B60000u, 46u}, // wnu -> Latn
- {0x776F0000u, 46u}, // wo -> Latn
- {0x85D60000u, 46u}, // wob -> Latn
- {0xC9D60000u, 46u}, // wos -> Latn
- {0xCA360000u, 46u}, // wrs -> Latn
+ {0xD1B60000u, 45u}, // wnu -> Latn
+ {0x776F0000u, 45u}, // wo -> Latn
+ {0x85D60000u, 45u}, // wob -> Latn
+ {0xC9D60000u, 45u}, // wos -> Latn
+ {0xCA360000u, 45u}, // wrs -> Latn
{0x9A560000u, 23u}, // wsg -> Gong
- {0xAA560000u, 46u}, // wsk -> Latn
+ {0xAA560000u, 45u}, // wsk -> Latn
{0xB2760000u, 19u}, // wtm -> Deva
{0xD2960000u, 29u}, // wuu -> Hans
- {0xD6960000u, 46u}, // wuv -> Latn
- {0x82D60000u, 46u}, // wwa -> Latn
- {0xD4170000u, 46u}, // xav -> Latn
- {0xA0370000u, 46u}, // xbi -> Latn
+ {0xD6960000u, 45u}, // wuv -> Latn
+ {0x82D60000u, 45u}, // wwa -> Latn
+ {0xD4170000u, 45u}, // xav -> Latn
+ {0xA0370000u, 45u}, // xbi -> Latn
{0xB8570000u, 15u}, // xco -> Chrs
{0xC4570000u, 12u}, // xcr -> Cari
- {0xC8970000u, 46u}, // xes -> Latn
- {0x78680000u, 46u}, // xh -> Latn
- {0x81770000u, 46u}, // xla -> Latn
- {0x89770000u, 50u}, // xlc -> Lyci
- {0x8D770000u, 51u}, // xld -> Lydi
+ {0xC8970000u, 45u}, // xes -> Latn
+ {0x78680000u, 45u}, // xh -> Latn
+ {0x81770000u, 45u}, // xla -> Latn
+ {0x89770000u, 49u}, // xlc -> Lyci
+ {0x8D770000u, 50u}, // xld -> Lydi
{0x95970000u, 22u}, // xmf -> Geor
- {0xB5970000u, 53u}, // xmn -> Mani
- {0xC5970000u, 55u}, // xmr -> Merc
- {0x81B70000u, 60u}, // xna -> Narb
+ {0xB5970000u, 52u}, // xmn -> Mani
+ {0xC5970000u, 54u}, // xmr -> Merc
+ {0x81B70000u, 59u}, // xna -> Narb
{0xC5B70000u, 19u}, // xnr -> Deva
- {0x99D70000u, 46u}, // xog -> Latn
- {0xB5D70000u, 46u}, // xon -> Latn
+ {0x99D70000u, 45u}, // xog -> Latn
+ {0xB5D70000u, 45u}, // xon -> Latn
{0xC5F70000u, 72u}, // xpr -> Prti
- {0x86370000u, 46u}, // xrb -> Latn
- {0x82570000u, 75u}, // xsa -> Sarb
- {0xA2570000u, 46u}, // xsi -> Latn
- {0xB2570000u, 46u}, // xsm -> Latn
+ {0x86370000u, 45u}, // xrb -> Latn
+ {0x82570000u, 76u}, // xsa -> Sarb
+ {0xA2570000u, 45u}, // xsi -> Latn
+ {0xB2570000u, 45u}, // xsm -> Latn
{0xC6570000u, 19u}, // xsr -> Deva
- {0x92D70000u, 46u}, // xwe -> Latn
- {0xB0180000u, 46u}, // yam -> Latn
- {0xB8180000u, 46u}, // yao -> Latn
- {0xBC180000u, 46u}, // yap -> Latn
- {0xC8180000u, 46u}, // yas -> Latn
- {0xCC180000u, 46u}, // yat -> Latn
- {0xD4180000u, 46u}, // yav -> Latn
- {0xE0180000u, 46u}, // yay -> Latn
- {0xE4180000u, 46u}, // yaz -> Latn
- {0x80380000u, 46u}, // yba -> Latn
- {0x84380000u, 46u}, // ybb -> Latn
- {0xE0380000u, 46u}, // yby -> Latn
- {0xC4980000u, 46u}, // yer -> Latn
- {0xC4D80000u, 46u}, // ygr -> Latn
- {0xD8D80000u, 46u}, // ygw -> Latn
+ {0x92D70000u, 45u}, // xwe -> Latn
+ {0xB0180000u, 45u}, // yam -> Latn
+ {0xB8180000u, 45u}, // yao -> Latn
+ {0xBC180000u, 45u}, // yap -> Latn
+ {0xC8180000u, 45u}, // yas -> Latn
+ {0xCC180000u, 45u}, // yat -> Latn
+ {0xD4180000u, 45u}, // yav -> Latn
+ {0xE0180000u, 45u}, // yay -> Latn
+ {0xE4180000u, 45u}, // yaz -> Latn
+ {0x80380000u, 45u}, // yba -> Latn
+ {0x84380000u, 45u}, // ybb -> Latn
+ {0xE0380000u, 45u}, // yby -> Latn
+ {0xC4980000u, 45u}, // yer -> Latn
+ {0xC4D80000u, 45u}, // ygr -> Latn
+ {0xD8D80000u, 45u}, // ygw -> Latn
{0x79690000u, 31u}, // yi -> Hebr
- {0xB9580000u, 46u}, // yko -> Latn
- {0x91780000u, 46u}, // yle -> Latn
- {0x99780000u, 46u}, // ylg -> Latn
- {0xAD780000u, 46u}, // yll -> Latn
- {0xAD980000u, 46u}, // yml -> Latn
- {0x796F0000u, 46u}, // yo -> Latn
- {0xB5D80000u, 46u}, // yon -> Latn
- {0x86380000u, 46u}, // yrb -> Latn
- {0x92380000u, 46u}, // yre -> Latn
- {0xAE380000u, 46u}, // yrl -> Latn
- {0xCA580000u, 46u}, // yss -> Latn
- {0x82980000u, 46u}, // yua -> Latn
+ {0xB9580000u, 45u}, // yko -> Latn
+ {0x91780000u, 45u}, // yle -> Latn
+ {0x99780000u, 45u}, // ylg -> Latn
+ {0xAD780000u, 45u}, // yll -> Latn
+ {0xAD980000u, 45u}, // yml -> Latn
+ {0x796F0000u, 45u}, // yo -> Latn
+ {0xB5D80000u, 45u}, // yon -> Latn
+ {0x86380000u, 45u}, // yrb -> Latn
+ {0x92380000u, 45u}, // yre -> Latn
+ {0xAE380000u, 45u}, // yrl -> Latn
+ {0xCA580000u, 45u}, // yss -> Latn
+ {0x82980000u, 45u}, // yua -> Latn
{0x92980000u, 30u}, // yue -> Hant
{0x9298434Eu, 29u}, // yue-CN -> Hans
- {0xA6980000u, 46u}, // yuj -> Latn
- {0xCE980000u, 46u}, // yut -> Latn
- {0xDA980000u, 46u}, // yuw -> Latn
- {0x7A610000u, 46u}, // za -> Latn
- {0x98190000u, 46u}, // zag -> Latn
+ {0xA6980000u, 45u}, // yuj -> Latn
+ {0xCE980000u, 45u}, // yut -> Latn
+ {0xDA980000u, 45u}, // yuw -> Latn
+ {0x7A610000u, 45u}, // za -> Latn
+ {0x98190000u, 45u}, // zag -> Latn
{0xA4790000u, 2u}, // zdj -> Arab
- {0x80990000u, 46u}, // zea -> Latn
- {0x9CD90000u, 89u}, // zgh -> Tfng
+ {0x80990000u, 45u}, // zea -> Latn
+ {0x9CD90000u, 90u}, // zgh -> Tfng
{0x7A680000u, 29u}, // zh -> Hans
{0x7A684155u, 30u}, // zh-AU -> Hant
{0x7A68424Eu, 30u}, // zh-BN -> Hant
@@ -1486,14 +1493,14 @@
{0x7A685457u, 30u}, // zh-TW -> Hant
{0x7A685553u, 30u}, // zh-US -> Hant
{0x7A68564Eu, 30u}, // zh-VN -> Hant
- {0xDCF90000u, 62u}, // zhx -> Nshu
- {0x81190000u, 46u}, // zia -> Latn
- {0xCD590000u, 41u}, // zkt -> Kits
- {0xB1790000u, 46u}, // zlm -> Latn
- {0xA1990000u, 46u}, // zmi -> Latn
- {0x91B90000u, 46u}, // zne -> Latn
- {0x7A750000u, 46u}, // zu -> Latn
- {0x83390000u, 46u}, // zza -> Latn
+ {0xDCF90000u, 61u}, // zhx -> Nshu
+ {0x81190000u, 45u}, // zia -> Latn
+ {0xCD590000u, 40u}, // zkt -> Kits
+ {0xB1790000u, 45u}, // zlm -> Latn
+ {0xA1990000u, 45u}, // zmi -> Latn
+ {0x91B90000u, 45u}, // zne -> Latn
+ {0x7A750000u, 45u}, // zu -> Latn
+ {0x83390000u, 45u}, // zza -> Latn
});
std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
@@ -1573,6 +1580,7 @@
0xCD21534E4C61746ELLU, // bjt_Latn_SN
0xB141434D4C61746ELLU, // bkm_Latn_CM
0xD14150484C61746ELLU, // bku_Latn_PH
+ 0x99614D594C61746ELLU, // blg_Latn_MY
0xCD61564E54617674LLU, // blt_Tavt_VN
0x626D4D4C4C61746ELLU, // bm_Latn_ML
0xC1814D4C4C61746ELLU, // bmq_Latn_ML
@@ -1748,7 +1756,7 @@
0x8D87434E506C7264LLU, // hmd_Plrd_CN
0x8DA7504B41726162LLU, // hnd_Arab_PK
0x91A7494E44657661LLU, // hne_Deva_IN
- 0xA5A74C41486D6E67LLU, // hnj_Hmng_LA
+ 0xA5A75553486D6E70LLU, // hnj_Hmnp_US
0xB5A750484C61746ELLU, // hnn_Latn_PH
0xB9A7504B41726162LLU, // hno_Arab_PK
0x686F50474C61746ELLU, // ho_Latn_PG
@@ -1797,7 +1805,7 @@
0x984A4E474C61746ELLU, // kcg_Latn_NG
0xA84A5A574C61746ELLU, // kck_Latn_ZW
0x906A545A4C61746ELLU, // kde_Latn_TZ
- 0x9C6A544741726162LLU, // kdh_Arab_TG
+ 0x9C6A54474C61746ELLU, // kdh_Latn_TG
0xCC6A544854686169LLU, // kdt_Thai_TH
0x808A43564C61746ELLU, // kea_Latn_CV
0xB48A434D4C61746ELLU, // ken_Latn_CM
@@ -1982,6 +1990,7 @@
0x6E725A414C61746ELLU, // nr_Latn_ZA
0xAA4D434143616E73LLU, // nsk_Cans_CA
0xBA4D5A414C61746ELLU, // nso_Latn_ZA
+ 0xCE4D494E546E7361LLU, // nst_Tnsa_IN
0xCA8D53534C61746ELLU, // nus_Latn_SS
0x6E7655534C61746ELLU, // nv_Latn_US
0xC2ED434E4C61746ELLU, // nxq_Latn_CN
@@ -1995,6 +2004,7 @@
0x6F7347454379726CLLU, // os_Cyrl_GE
0x824E55534F736765LLU, // osa_Osge_US
0xAA6E4D4E4F726B68LLU, // otk_Orkh_MN
+ 0xA28E8C814F756772LLU, // oui_Ougr_143
0x7061504B41726162LLU, // pa_Arab_PK
0x7061494E47757275LLU, // pa_Guru_IN
0x980F50484C61746ELLU, // pag_Latn_PH
@@ -2029,7 +2039,7 @@
0x945152454C61746ELLU, // rcf_Latn_RE
0xA49149444C61746ELLU, // rej_Latn_ID
0xB4D149544C61746ELLU, // rgn_Latn_IT
- 0x98F14D4D41726162LLU, // rhg_Arab_MM
+ 0x98F14D4D526F6867LLU, // rhg_Rohg_MM
0x8111494E4C61746ELLU, // ria_Latn_IN
0x95114D4154666E67LLU, // rif_Tfng_MA
0xC9314E5044657661LLU, // rjs_Deva_NP
@@ -2172,6 +2182,7 @@
0xAEB354564C61746ELLU, // tvl_Latn_TV
0xC2D34E454C61746ELLU, // twq_Latn_NE
0x9AF3434E54616E67LLU, // txg_Tang_CN
+ 0xBAF3494E546F746FLLU, // txo_Toto_IN
0x747950464C61746ELLU, // ty_Latn_PF
0xD71352554379726CLLU, // tyv_Cyrl_RU
0xB3334D414C61746ELLU, // tzm_Latn_MA
@@ -2256,6 +2267,7 @@
});
const std::unordered_map<uint32_t, uint32_t> ARAB_PARENTS({
+ {0x61724145u, 0x61729420u}, // ar-AE -> ar-015
{0x6172445Au, 0x61729420u}, // ar-DZ -> ar-015
{0x61724548u, 0x61729420u}, // ar-EH -> ar-015
{0x61724C59u, 0x61729420u}, // ar-LY -> ar-015
@@ -2279,7 +2291,6 @@
{0x656E4253u, 0x656E8400u}, // en-BS -> en-001
{0x656E4257u, 0x656E8400u}, // en-BW -> en-001
{0x656E425Au, 0x656E8400u}, // en-BZ -> en-001
- {0x656E4341u, 0x656E8400u}, // en-CA -> en-001
{0x656E4343u, 0x656E8400u}, // en-CC -> en-001
{0x656E4348u, 0x656E80A1u}, // en-CH -> en-150
{0x656E434Bu, 0x656E8400u}, // en-CK -> en-001
@@ -2332,7 +2343,6 @@
{0x656E4E55u, 0x656E8400u}, // en-NU -> en-001
{0x656E4E5Au, 0x656E8400u}, // en-NZ -> en-001
{0x656E5047u, 0x656E8400u}, // en-PG -> en-001
- {0x656E5048u, 0x656E8400u}, // en-PH -> en-001
{0x656E504Bu, 0x656E8400u}, // en-PK -> en-001
{0x656E504Eu, 0x656E8400u}, // en-PN -> en-001
{0x656E5057u, 0x656E8400u}, // en-PW -> en-001
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c7f5696..60f4a5a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -32,6 +32,7 @@
import android.app.PendingIntent;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -6790,30 +6791,56 @@
/**
* Returns a list of audio formats that corresponds to encoding formats
- * supported on offload path for A2DP playback.
+ * supported on offload path for A2DP and LE audio playback.
*
+ * @param deviceType Indicates the target device type {@link AudioSystem.DeviceType}
* @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
- * supported for offload A2DP playback
+ * supported for offload A2DP playback or a list of {@link BluetoothLeAudioCodecConfig}
+ * objects containing encoding formats supported for offload LE Audio playback
* @hide
*/
- public List<BluetoothCodecConfig> getHwOffloadEncodingFormatsSupportedForA2DP() {
+ public List<?> getHwOffloadFormatsSupportedForBluetoothMedia(
+ @AudioSystem.DeviceType int deviceType) {
ArrayList<Integer> formatsList = new ArrayList<Integer>();
- ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<BluetoothCodecConfig>();
+ ArrayList<BluetoothCodecConfig> a2dpCodecConfigList = new ArrayList<BluetoothCodecConfig>();
+ ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList =
+ new ArrayList<BluetoothLeAudioCodecConfig>();
- int status = AudioSystem.getHwOffloadEncodingFormatsSupportedForA2DP(formatsList);
+ if (deviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
+ && deviceType != AudioSystem.DEVICE_OUT_BLE_HEADSET) {
+ throw new IllegalArgumentException(
+ "Illegal devicetype for the getHwOffloadFormatsSupportedForBluetoothMedia");
+ }
+
+ int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(deviceType,
+ formatsList);
if (status != AudioManager.SUCCESS) {
- Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
- return codecConfigList;
+ Log.e(TAG, "getHwOffloadFormatsSupportedForBluetoothMedia for deviceType "
+ + deviceType + " failed:" + status);
+ return a2dpCodecConfigList;
}
- for (Integer format : formatsList) {
- int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
- if (btSourceCodec
- != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
- codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
+ if (deviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+ for (Integer format : formatsList) {
+ int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
+ if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
+ a2dpCodecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
+ }
}
+ return a2dpCodecConfigList;
+ } else if (deviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) {
+ for (Integer format : formatsList) {
+ int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
+ if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
+ leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
+ .setCodecType(btLeAudioCodec)
+ .build());
+ }
+ }
+ return leAudioCodecConfigList;
}
- return codecConfigList;
+ Log.e(TAG, "Input deviceType " + deviceType + " doesn't support.");
+ return a2dpCodecConfigList;
}
// Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 69d1889..f0e42c0 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -21,6 +21,7 @@
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -229,6 +230,9 @@
public static final int AUDIO_FORMAT_APTX_HD = 0x21000000;
/** @hide */
public static final int AUDIO_FORMAT_LDAC = 0x23000000;
+ /** @hide */
+ public static final int AUDIO_FORMAT_LC3 = 0x2B000000;
+
/** @hide */
@IntDef(flag = false, prefix = "AUDIO_FORMAT_", value = {
@@ -238,11 +242,26 @@
AUDIO_FORMAT_SBC,
AUDIO_FORMAT_APTX,
AUDIO_FORMAT_APTX_HD,
- AUDIO_FORMAT_LDAC }
+ AUDIO_FORMAT_LDAC}
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioFormatNativeEnumForBtCodec {}
+ /** @hide */
+ @IntDef(flag = false, prefix = "AUDIO_FORMAT_", value = {
+ AUDIO_FORMAT_LC3}
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AudioFormatNativeEnumForBtLeAudioCodec {}
+
+ /** @hide */
+ @IntDef(flag = false, prefix = "DEVICE_", value = {
+ DEVICE_OUT_BLUETOOTH_A2DP,
+ DEVICE_OUT_BLE_HEADSET}
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeviceType {}
+
/**
* @hide
* Convert audio format enum values to Bluetooth codec values
@@ -264,6 +283,21 @@
/**
* @hide
+ * Convert audio format enum values to Bluetooth LE audio codec values
+ */
+ public static int audioFormatToBluetoothLeAudioSourceCodec(
+ @AudioFormatNativeEnumForBtLeAudioCodec int audioFormat) {
+ switch (audioFormat) {
+ case AUDIO_FORMAT_LC3: return BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3;
+ default:
+ Log.e(TAG, "Unknown audio format 0x" + Integer.toHexString(audioFormat)
+ + " for conversion to BT LE audio codec");
+ return BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID;
+ }
+ }
+
+ /**
+ * @hide
* Convert a Bluetooth codec to an audio format enum
* @param btCodec the codec to convert.
* @return the audio format, or {@link #AUDIO_FORMAT_DEFAULT} if unknown
@@ -1754,10 +1788,10 @@
/**
* @hide
- * Returns a list of audio formats (codec) supported on the A2DP offload path.
+ * Returns a list of audio formats (codec) supported on the A2DP and LE audio offload path.
*/
- public static native int getHwOffloadEncodingFormatsSupportedForA2DP(
- ArrayList<Integer> formatList);
+ public static native int getHwOffloadFormatsSupportedForBluetoothMedia(
+ @DeviceType int deviceType, ArrayList<Integer> formatList);
/** @hide */
public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled);
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 1616c03..54e19db 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -163,6 +163,14 @@
* {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
* </td>
* </tr>
+ * <tr>
+ * <td>{@link android.graphics.ImageFormat#YCBCR_P010 YCBCR_P010}</td>
+ * <td>1</td>
+ * <td>P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+ * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
+ * little-endian value, with the lower 6 bits set to zero.
+ * </td>
+ * </tr>
* </table>
*
* @see android.graphics.ImageFormat
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index de31a7f..72dd2bd 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -5107,7 +5107,6 @@
public MediaImage(
@NonNull ByteBuffer buffer, @NonNull ByteBuffer info, boolean readOnly,
long timestamp, int xOffset, int yOffset, @Nullable Rect cropRect) {
- mFormat = ImageFormat.YUV_420_888;
mTimestamp = timestamp;
mIsImageValid = true;
mIsReadOnly = buffer.isReadOnly();
@@ -5120,6 +5119,11 @@
mBufferContext = 0;
+ int cbPlaneOffset = -1;
+ int crPlaneOffset = -1;
+ int planeOffsetInc = -1;
+ int pixelStride = -1;
+
// read media-info. See MediaImage2
if (info.remaining() == 104) {
int type = info.getInt();
@@ -5137,14 +5141,27 @@
"unsupported size: " + mWidth + "x" + mHeight);
}
int bitDepth = info.getInt();
- if (bitDepth != 8) {
+ if (bitDepth != 8 && bitDepth != 10) {
throw new UnsupportedOperationException("unsupported bit depth: " + bitDepth);
}
int bitDepthAllocated = info.getInt();
- if (bitDepthAllocated != 8) {
+ if (bitDepthAllocated != 8 && bitDepthAllocated != 16) {
throw new UnsupportedOperationException(
"unsupported allocated bit depth: " + bitDepthAllocated);
}
+ if (bitDepth == 8 && bitDepthAllocated == 8) {
+ mFormat = ImageFormat.YUV_420_888;
+ planeOffsetInc = 1;
+ pixelStride = 2;
+ } else if (bitDepth == 10 && bitDepthAllocated == 16) {
+ mFormat = ImageFormat.YCBCR_P010;
+ planeOffsetInc = 2;
+ pixelStride = 4;
+ } else {
+ throw new UnsupportedOperationException("couldn't infer ImageFormat"
+ + " bitDepth: " + bitDepth + " bitDepthAllocated: " + bitDepthAllocated);
+ }
+
mPlanes = new MediaPlane[numPlanes];
for (int ix = 0; ix < numPlanes; ix++) {
int planeOffset = info.getInt();
@@ -5166,12 +5183,31 @@
buffer.limit(buffer.position() + Utils.divUp(bitDepth, 8)
+ (mHeight / vert - 1) * rowInc + (mWidth / horiz - 1) * colInc);
mPlanes[ix] = new MediaPlane(buffer.slice(), rowInc, colInc);
+ if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010)
+ && ix == 1) {
+ cbPlaneOffset = planeOffset;
+ } else if ((mFormat == ImageFormat.YUV_420_888
+ || mFormat == ImageFormat.YCBCR_P010) && ix == 2) {
+ crPlaneOffset = planeOffset;
+ }
}
} else {
throw new UnsupportedOperationException(
"unsupported info length: " + info.remaining());
}
+ // Validate chroma semiplanerness.
+ if (mFormat == ImageFormat.YCBCR_P010) {
+ if (crPlaneOffset != cbPlaneOffset + planeOffsetInc) {
+ throw new UnsupportedOperationException("Invalid plane offsets"
+ + " cbPlaneOffset: " + cbPlaneOffset + " crPlaneOffset: " + crPlaneOffset);
+ }
+ if (mPlanes[1].getPixelStride() != pixelStride
+ || mPlanes[2].getPixelStride() != pixelStride) {
+ throw new UnsupportedOperationException("Invalid pixelStride");
+ }
+ }
+
if (cropRect == null) {
cropRect = new Rect(0, 0, mWidth, mHeight);
}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl
index ae63462..0c8e431 100644
--- a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl
@@ -41,5 +41,5 @@
interface ISecureElementService {
String[] getReaders();
android.se.omapi.ISecureElementReader getReader(in String reader);
- boolean[] isNFCEventAllowed(in String reader, in byte[] aid, in String[] packageNames);
+ boolean[] isNfcEventAllowed(in String reader, in byte[] aid, in String[] packageNames, in int userId);
}
diff --git a/omapi/aidl/android/se/omapi/ISecureElementService.aidl b/omapi/aidl/android/se/omapi/ISecureElementService.aidl
index 61ae481..13707ec 100644
--- a/omapi/aidl/android/se/omapi/ISecureElementService.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementService.aidl
@@ -52,7 +52,7 @@
* Checks if the application defined by the package name is allowed to
* receive NFC transaction events for the defined AID.
*/
- boolean[] isNFCEventAllowed(in String reader, in byte[] aid,
- in String[] packageNames);
+ boolean[] isNfcEventAllowed(in String reader, in byte[] aid,
+ in String[] packageNames, in int userId);
}
diff --git a/packages/ConnectivityT/OWNERS b/packages/ConnectivityT/OWNERS
new file mode 100644
index 0000000..4862377
--- /dev/null
+++ b/packages/ConnectivityT/OWNERS
@@ -0,0 +1 @@
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
\ No newline at end of file
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 801b490..a3eb0ecc 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -251,7 +251,7 @@
if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
root.flags |= Root.FLAG_HAS_SETTINGS;
}
- if (volume.isVisibleForRead(userId)) {
+ if (volume.isVisibleForUser(userId)) {
root.visiblePath = volume.getPathForUser(userId);
} else {
root.visiblePath = null;
diff --git a/packages/Nsd/OWNERS b/packages/Nsd/OWNERS
new file mode 100644
index 0000000..4862377
--- /dev/null
+++ b/packages/Nsd/OWNERS
@@ -0,0 +1 @@
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
\ No newline at end of file
diff --git a/packages/Nsd/framework/Android.bp b/packages/Nsd/framework/Android.bp
new file mode 100644
index 0000000..2363a9f
--- /dev/null
+++ b/packages/Nsd/framework/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: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "framework-connectivity-nsd-internal-sources",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.aidl",
+ ],
+ path: "src",
+ visibility: [
+ "//visibility:private",
+ ],
+}
+
+filegroup {
+ name: "framework-connectivity-nsd-aidl-export-sources",
+ srcs: [
+ "aidl-export/**/*.aidl",
+ ],
+ path: "aidl-export",
+ visibility: [
+ "//visibility:private",
+ ],
+}
+
+filegroup {
+ name: "framework-connectivity-nsd-sources",
+ srcs: [
+ ":framework-connectivity-nsd-internal-sources",
+ ":framework-connectivity-nsd-aidl-export-sources",
+ ],
+ visibility: [
+ "//frameworks/base",
+ ],
+}
diff --git a/core/java/android/net/nsd/NsdServiceInfo.aidl b/packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl
similarity index 100%
rename from core/java/android/net/nsd/NsdServiceInfo.aidl
rename to packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl
diff --git a/core/java/android/net/nsd/INsdManager.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl
similarity index 100%
rename from core/java/android/net/nsd/INsdManager.aidl
rename to packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl
diff --git a/core/java/android/net/nsd/INsdManagerCallback.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl
similarity index 100%
rename from core/java/android/net/nsd/INsdManagerCallback.aidl
rename to packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl
diff --git a/core/java/android/net/nsd/INsdServiceConnector.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl
similarity index 100%
rename from core/java/android/net/nsd/INsdServiceConnector.aidl
rename to packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl
diff --git a/core/java/android/net/nsd/NsdManager.java b/packages/Nsd/framework/src/android/net/nsd/NsdManager.java
similarity index 100%
rename from core/java/android/net/nsd/NsdManager.java
rename to packages/Nsd/framework/src/android/net/nsd/NsdManager.java
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java
similarity index 100%
rename from core/java/android/net/nsd/NsdServiceInfo.java
rename to packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java
diff --git a/packages/Nsd/service/Android.bp b/packages/Nsd/service/Android.bp
new file mode 100644
index 0000000..529f58d
--- /dev/null
+++ b/packages/Nsd/service/Android.bp
@@ -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 {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "services.connectivity-nsd-sources",
+ srcs: [
+ "src/**/*.java",
+ ],
+ path: "src",
+ visibility: [
+ "//frameworks/base/services/core",
+ ],
+}
diff --git a/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java b/packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java
similarity index 100%
rename from services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
rename to packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java
similarity index 93%
rename from services/core/java/com/android/server/NativeDaemonConnector.java
rename to packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java
index eac767f..ec8d779 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java
@@ -20,18 +20,15 @@
import android.net.LocalSocketAddress;
import android.os.Build;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.util.LocalLog;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-import com.android.server.power.ShutdownThread;
-import com.google.android.collect.Lists;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -40,19 +37,19 @@
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.LinkedList;
+import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.LinkedList;
-import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Generic connector class for interfacing with a native daemon which uses the
* {@code libsysutils} FrameworkListener protocol.
*/
-final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {
+final class NativeDaemonConnector implements Runnable, Handler.Callback {
private final static boolean VDBG = false;
private final String TAG;
@@ -85,13 +82,6 @@
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
- this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl,
- FgThread.get().getLooper());
- }
-
- NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
- int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
- Looper looper) {
mCallbacks = callbacks;
mSocket = socket;
mResponseQueue = new ResponseQueue(responseQueueSize);
@@ -99,15 +89,17 @@
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(true);
}
- mLooper = looper;
mSequenceNumber = new AtomicInteger(0);
TAG = logTag != null ? logTag : "NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
+ final HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mLooper = thread.getLooper();
}
/**
* Enable Set debugging mode, which causes messages to also be written to both
- * {@link Slog} in addition to internal log.
+ * {@link Log} in addition to internal log.
*/
public void setDebug(boolean debug) {
mDebug = debug;
@@ -126,7 +118,9 @@
* calls while holding a lock on the given object.
*/
public void setWarnIfHeld(Object warnIfHeld) {
- Preconditions.checkState(mWarnIfHeld == null);
+ if (mWarnIfHeld != null) {
+ throw new IllegalStateException("warnIfHeld is already set.");
+ }
mWarnIfHeld = Objects.requireNonNull(warnIfHeld);
}
@@ -135,23 +129,15 @@
mCallbackHandler = new Handler(mLooper, this);
while (true) {
- if (isShuttingDown()) break;
try {
listenToSocket();
} catch (Exception e) {
loge("Error in NativeDaemonConnector: " + e);
- if (isShuttingDown()) break;
SystemClock.sleep(5000);
}
}
}
- private static boolean isShuttingDown() {
- String shutdownAct = SystemProperties.get(
- ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
- return shutdownAct != null && shutdownAct.length() > 0;
- }
-
@Override
public boolean handleMessage(Message msg) {
final String event = (String) msg.obj;
@@ -183,7 +169,7 @@
// In order to ensure that unprivileged apps aren't able to impersonate native daemons on
// production devices, even if said native daemons ill-advisedly pick a socket name that
// starts with __test__, only allow this on debug builds.
- if (mSocket.startsWith("__test__") && Build.IS_DEBUGGABLE) {
+ if (mSocket.startsWith("__test__") && Build.isDebuggable()) {
return new LocalSocketAddress(mSocket);
} else {
return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);
@@ -375,7 +361,7 @@
try {
latch.await();
} catch (InterruptedException e) {
- Slog.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e);
+ Log.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e);
}
}
@@ -462,13 +448,13 @@
public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
- Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Log.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
}
final long startTime = SystemClock.elapsedRealtime();
- final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
+ final ArrayList<NativeDaemonEvent> events = new ArrayList<>();
final StringBuilder rawBuilder = new StringBuilder();
final StringBuilder logBuilder = new StringBuilder();
@@ -571,7 +557,7 @@
*/
public static class Command {
private String mCmd;
- private ArrayList<Object> mArguments = Lists.newArrayList();
+ private ArrayList<Object> mArguments = new ArrayList<>();
public Command(String cmd, Object... args) {
mCmd = cmd;
@@ -586,11 +572,6 @@
}
}
- /** {@inheritDoc} */
- public void monitor() {
- synchronized (mDaemonLock) { }
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mLocalLog.dump(fd, pw, args);
pw.println();
@@ -598,12 +579,12 @@
}
private void log(String logstring) {
- if (mDebug) Slog.d(TAG, logstring);
+ if (mDebug) Log.d(TAG, logstring);
mLocalLog.log(logstring);
}
private void loge(String logstring) {
- Slog.e(TAG, logstring);
+ Log.e(TAG, logstring);
mLocalLog.log(logstring);
}
@@ -659,12 +640,12 @@
if (found == null) {
// didn't find it - make sure our queue isn't too big before adding
while (mPendingCmds.size() >= mMaxCount) {
- Slog.e("NativeDaemonConnector.ResponseQueue",
+ Log.e("NativeDaemonConnector.ResponseQueue",
"more buffered than allowed: " + mPendingCmds.size() +
" >= " + mMaxCount);
// let any waiter timeout waiting for this
PendingCmd pendingCmd = mPendingCmds.remove();
- Slog.e("NativeDaemonConnector.ResponseQueue",
+ Log.e("NativeDaemonConnector.ResponseQueue",
"Removing request: " + pendingCmd.logCmd + " (" +
pendingCmd.cmdNum + ")");
}
@@ -706,7 +687,7 @@
result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {}
if (result == null) {
- Slog.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response");
+ Log.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response");
}
return result;
}
diff --git a/services/core/java/com/android/server/NativeDaemonConnectorException.java b/packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java
similarity index 100%
rename from services/core/java/com/android/server/NativeDaemonConnectorException.java
rename to packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java
diff --git a/services/core/java/com/android/server/NativeDaemonEvent.java b/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java
similarity index 93%
rename from services/core/java/com/android/server/NativeDaemonEvent.java
rename to packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java
index e6feda3..5683694 100644
--- a/services/core/java/com/android/server/NativeDaemonEvent.java
+++ b/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java
@@ -16,8 +16,7 @@
package com.android.server;
-import android.util.Slog;
-import com.google.android.collect.Lists;
+import android.util.Log;
import java.io.FileDescriptor;
import java.util.ArrayList;
@@ -179,7 +178,7 @@
* {@link #getMessage()} for any events matching the requested code.
*/
public static String[] filterMessageList(NativeDaemonEvent[] events, int matchCode) {
- final ArrayList<String> result = Lists.newArrayList();
+ final ArrayList<String> result = new ArrayList<>();
for (NativeDaemonEvent event : events) {
if (event.getCode() == matchCode) {
result.add(event.getMessage());
@@ -212,7 +211,7 @@
int wordEnd = -1;
boolean quoted = false;
- if (DEBUG_ROUTINE) Slog.e(LOGTAG, "parsing '" + rawEvent + "'");
+ if (DEBUG_ROUTINE) Log.e(LOGTAG, "parsing '" + rawEvent + "'");
if (rawEvent.charAt(current) == '\"') {
quoted = true;
current++;
@@ -240,14 +239,14 @@
word = word.replace("\\\\", "\\");
word = word.replace("\\\"", "\"");
- if (DEBUG_ROUTINE) Slog.e(LOGTAG, "found '" + word + "'");
+ if (DEBUG_ROUTINE) Log.e(LOGTAG, "found '" + word + "'");
parsed.add(word);
// find the beginning of the next word - either of these options
int nextSpace = rawEvent.indexOf(' ', current);
int nextQuote = rawEvent.indexOf(" \"", current);
if (DEBUG_ROUTINE) {
- Slog.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote);
+ Log.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote);
}
if (nextQuote > -1 && nextQuote <= nextSpace) {
quoted = true;
@@ -259,8 +258,8 @@
}
} // else we just start the next word after the current and read til the end
if (DEBUG_ROUTINE) {
- Slog.e(LOGTAG, "next loop - current=" + current +
- ", length=" + length + ", quoted=" + quoted);
+ Log.e(LOGTAG, "next loop - current=" + current
+ + ", length=" + length + ", quoted=" + quoted);
}
}
return parsed.toArray(new String[parsed.size()]);
diff --git a/services/core/java/com/android/server/NativeDaemonTimeoutException.java b/packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java
similarity index 100%
rename from services/core/java/com/android/server/NativeDaemonTimeoutException.java
rename to packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java
diff --git a/services/core/java/com/android/server/NsdService.java b/packages/Nsd/service/src/com/android/server/NsdService.java
similarity index 89%
rename from services/core/java/com/android/server/NsdService.java
rename to packages/Nsd/service/src/com/android/server/NsdService.java
index 3e02084..497107d 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/packages/Nsd/service/src/com/android/server/NsdService.java
@@ -16,11 +16,9 @@
package com.android.server;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.database.ContentObserver;
-import android.net.Uri;
+import android.content.pm.PackageManager;
import android.net.nsd.INsdManager;
import android.net.nsd.INsdManagerCallback;
import android.net.nsd.INsdServiceConnector;
@@ -32,16 +30,13 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.util.Base64;
import android.util.Log;
import android.util.Pair;
-import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.net.module.util.DnsSdTxtRecord;
@@ -67,7 +62,6 @@
private static final long CLEANUP_DELAY_MS = 10000;
private final Context mContext;
- private final NsdSettings mNsdSettings;
private final NsdStateMachine mNsdStateMachine;
private final DaemonConnection mDaemon;
private final NativeCallbackReceiver mDaemonCallback;
@@ -122,30 +116,14 @@
this.removeMessages(NsdManager.DAEMON_CLEANUP);
}
- /**
- * Observes the NSD on/off setting, and takes action when changed.
- */
- private void registerForNsdSetting() {
- final ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- notifyEnabled(isNsdEnabled());
- }
- };
-
- final Uri uri = Settings.Global.getUriFor(Settings.Global.NSD_ON);
- mNsdSettings.registerContentObserver(uri, contentObserver);
- }
-
NsdStateMachine(String name, Handler handler) {
super(name, handler);
addState(mDefaultState);
addState(mDisabledState, mDefaultState);
addState(mEnabledState, mDefaultState);
- State initialState = isNsdEnabled() ? mEnabledState : mDisabledState;
+ State initialState = mEnabledState;
setInitialState(initialState);
setLogRecSize(25);
- registerForNsdSetting();
}
class DefaultState extends State {
@@ -228,7 +206,7 @@
break;
case NsdManager.NATIVE_DAEMON_EVENT:
default:
- Slog.e(TAG, "Unhandled " + msg);
+ Log.e(TAG, "Unhandled " + msg);
return NOT_HANDLED;
}
return HANDLED;
@@ -274,7 +252,7 @@
private boolean requestLimitReached(ClientInfo clientInfo) {
if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
- if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
+ if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo);
return true;
}
return false;
@@ -307,7 +285,7 @@
transitionTo(mDisabledState);
break;
case NsdManager.DISCOVER_SERVICES:
- if (DBG) Slog.d(TAG, "Discover services");
+ if (DBG) Log.d(TAG, "Discover services");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
@@ -321,8 +299,8 @@
id = getUniqueId();
if (discoverServices(id, args.serviceInfo.getServiceType())) {
if (DBG) {
- Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
- args.serviceInfo.getServiceType());
+ Log.d(TAG, "Discover " + msg.arg2 + " " + id
+ + args.serviceInfo.getServiceType());
}
storeRequestMap(clientId, id, clientInfo, msg.what);
clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo);
@@ -333,7 +311,7 @@
}
break;
case NsdManager.STOP_DISCOVERY:
- if (DBG) Slog.d(TAG, "Stop service discovery");
+ if (DBG) Log.d(TAG, "Stop service discovery");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
@@ -353,7 +331,7 @@
}
break;
case NsdManager.REGISTER_SERVICE:
- if (DBG) Slog.d(TAG, "Register service");
+ if (DBG) Log.d(TAG, "Register service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
if (requestLimitReached(clientInfo)) {
@@ -365,7 +343,7 @@
maybeStartDaemon();
id = getUniqueId();
if (registerService(id, args.serviceInfo)) {
- if (DBG) Slog.d(TAG, "Register " + clientId + " " + id);
+ if (DBG) Log.d(TAG, "Register " + clientId + " " + id);
storeRequestMap(clientId, id, clientInfo, msg.what);
// Return success after mDns reports success
} else {
@@ -375,11 +353,11 @@
}
break;
case NsdManager.UNREGISTER_SERVICE:
- if (DBG) Slog.d(TAG, "unregister service");
+ if (DBG) Log.d(TAG, "unregister service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
if (clientInfo == null) {
- Slog.e(TAG, "Unknown connector in unregistration");
+ Log.e(TAG, "Unknown connector in unregistration");
break;
}
id = clientInfo.mClientIds.get(clientId);
@@ -392,7 +370,7 @@
}
break;
case NsdManager.RESOLVE_SERVICE:
- if (DBG) Slog.d(TAG, "Resolve service");
+ if (DBG) Log.d(TAG, "Resolve service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
@@ -430,7 +408,7 @@
ClientInfo clientInfo = mIdToClientInfoMap.get(id);
if (clientInfo == null) {
String name = NativeResponseCode.nameOf(code);
- Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
+ Log.e(TAG, String.format("id %d for %s has no client mapping", id, name));
return false;
}
@@ -441,14 +419,14 @@
// SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
// and we may get in this situation.
String name = NativeResponseCode.nameOf(code);
- Slog.d(TAG, String.format(
+ Log.d(TAG, String.format(
"Notification %s for listener id %d that is no longer active",
name, id));
return false;
}
if (DBG) {
String name = NativeResponseCode.nameOf(code);
- Slog.d(TAG, String.format("Native daemon message %s: %s", name, raw));
+ Log.d(TAG, String.format("Native daemon message %s: %s", name, raw));
}
switch (code) {
case NativeResponseCode.SERVICE_FOUND:
@@ -492,7 +470,7 @@
++index;
}
if (index >= cooked[2].length()) {
- Slog.e(TAG, "Invalid service found " + raw);
+ Log.e(TAG, "Invalid service found " + raw);
break;
}
String name = cooked[2].substring(0, index);
@@ -562,13 +540,13 @@
char c = s.charAt(i);
if (c == '\\') {
if (++i >= s.length()) {
- Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
+ Log.e(TAG, "Unexpected end of escape sequence in: " + s);
break;
}
c = s.charAt(i);
if (c != '.' && c != '\\') {
if (i + 2 >= s.length()) {
- Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
+ Log.e(TAG, "Unexpected end of escape sequence in: " + s);
break;
}
c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
@@ -581,11 +559,9 @@
}
@VisibleForTesting
- NsdService(Context ctx, NsdSettings settings, Handler handler,
- DaemonConnectionSupplier fn, long cleanupDelayMs) {
+ NsdService(Context ctx, Handler handler, DaemonConnectionSupplier fn, long cleanupDelayMs) {
mCleanupDelayMs = cleanupDelayMs;
mContext = ctx;
- mNsdSettings = settings;
mNsdStateMachine = new NsdStateMachine(TAG, handler);
mNsdStateMachine.start();
mDaemonCallback = new NativeCallbackReceiver();
@@ -593,12 +569,11 @@
}
public static NsdService create(Context context) throws InterruptedException {
- NsdSettings settings = NsdSettings.makeDefault(context);
HandlerThread thread = new HandlerThread(TAG);
thread.start();
Handler handler = new Handler(thread.getLooper());
- NsdService service = new NsdService(context, settings, handler,
- DaemonConnection::new, CLEANUP_DELAY_MS);
+ NsdService service =
+ new NsdService(context, handler, DaemonConnection::new, CLEANUP_DELAY_MS);
service.mDaemonCallback.awaitConnection();
return service;
}
@@ -670,10 +645,6 @@
}
}
- private void notifyEnabled(boolean isEnabled) {
- mNsdStateMachine.sendMessage(isEnabled ? NsdManager.ENABLE : NsdManager.DISABLE);
- }
-
private void sendNsdStateChangeBroadcast(boolean isEnabled) {
final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -682,14 +653,6 @@
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private boolean isNsdEnabled() {
- boolean ret = mNsdSettings.isEnabled();
- if (DBG) {
- Slog.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled"));
- }
- return ret;
- }
-
private int getUniqueId() {
if (++mUniqueId == INVALID_ID) return ++mUniqueId;
return mUniqueId;
@@ -795,12 +758,12 @@
*/
public boolean execute(Object... args) {
if (DBG) {
- Slog.d(TAG, "mdnssd " + Arrays.toString(args));
+ Log.d(TAG, "mdnssd " + Arrays.toString(args));
}
try {
mNativeConnector.execute("mdnssd", args);
} catch (NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e);
+ Log.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e);
return false;
}
return true;
@@ -831,7 +794,7 @@
private boolean registerService(int regId, NsdServiceInfo service) {
if (DBG) {
- Slog.d(TAG, "registerService: " + regId + " " + service);
+ Log.d(TAG, "registerService: " + regId + " " + service);
}
String name = service.getServiceName();
String type = service.getServiceType();
@@ -880,7 +843,12 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump " + TAG
+ + " due to missing android.permission.DUMP permission");
+ return;
+ }
for (ClientInfo client : mClients.values()) {
pw.println("Client Info");
@@ -909,7 +877,7 @@
private ClientInfo(INsdManagerCallback cb) {
mCb = cb;
- if (DBG) Slog.d(TAG, "New client");
+ if (DBG) Log.d(TAG, "New client");
}
@Override
@@ -943,8 +911,10 @@
clientId = mClientIds.keyAt(i);
globalId = mClientIds.valueAt(i);
mIdToClientInfoMap.remove(globalId);
- if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
- " global-ID " + globalId + " type " + mClientRequests.get(clientId));
+ if (DBG) {
+ Log.d(TAG, "Terminating client-ID " + clientId
+ + " global-ID " + globalId + " type " + mClientRequests.get(clientId));
+ }
switch (mClientRequests.get(clientId)) {
case NsdManager.DISCOVER_SERVICES:
stopServiceDiscovery(globalId);
@@ -1069,35 +1039,4 @@
}
}
}
-
- /**
- * Interface which encapsulates dependencies of NsdService that are hard to mock, hard to
- * override, or have side effects on global state in unit tests.
- */
- @VisibleForTesting
- public interface NsdSettings {
- boolean isEnabled();
- void putEnabledStatus(boolean isEnabled);
- void registerContentObserver(Uri uri, ContentObserver observer);
-
- static NsdSettings makeDefault(Context context) {
- final ContentResolver resolver = context.getContentResolver();
- return new NsdSettings() {
- @Override
- public boolean isEnabled() {
- return Settings.Global.getInt(resolver, Settings.Global.NSD_ON, 1) == 1;
- }
-
- @Override
- public void putEnabledStatus(boolean isEnabled) {
- Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0);
- }
-
- @Override
- public void registerContentObserver(Uri uri, ContentObserver observer) {
- resolver.registerContentObserver(uri, false, observer);
- }
- };
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java
rename to packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 3c78560..99e3160 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -28,13 +28,16 @@
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
+import android.os.Build;
import android.os.ParcelUuid;
import android.util.Log;
+import androidx.annotation.RequiresApi;
+
import com.android.settingslib.R;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
public class A2dpProfile implements LocalBluetoothProfile {
@@ -226,6 +229,10 @@
return support == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED;
}
+ /**
+ * @return whether high quality audio is enabled or not
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
if (bluetoothDevice == null) {
@@ -271,6 +278,13 @@
}
}
+ /**
+ * Gets the label associated with the codec of a Bluetooth device.
+ *
+ * @param device to get codec label from
+ * @return the label associated with the device codec
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
@@ -280,18 +294,18 @@
}
// We want to get the highest priority codec, since that's the one that will be used with
// this device, and see if it is high-quality (ie non-mandatory).
- BluetoothCodecConfig[] selectable = null;
+ List<BluetoothCodecConfig> selectable = null;
if (mService.getCodecStatus(device) != null) {
selectable = mService.getCodecStatus(device).getCodecsSelectableCapabilities();
// To get the highest priority, we sort in reverse.
- Arrays.sort(selectable,
+ Collections.sort(selectable,
(a, b) -> {
return b.getCodecPriority() - a.getCodecPriority();
});
}
- final BluetoothCodecConfig codecConfig = (selectable == null || selectable.length < 1)
- ? null : selectable[0];
+ final BluetoothCodecConfig codecConfig = (selectable == null || selectable.size() < 1)
+ ? null : selectable.get(0);
final int codecType = (codecConfig == null || codecConfig.isMandatoryCodec())
? BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID : codecConfig.getCodecType();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 1df1bce..389892e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -307,7 +307,8 @@
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
cachedDevice = mDeviceManager.addDevice(device);
- Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice");
+ Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice "
+ + cachedDevice.getDevice().getAnonymizedAddress());
} else if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
&& !cachedDevice.getDevice().isConnected()) {
// Dispatch device add callback to show bonded but
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 021ba224..ddee433 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -21,7 +21,6 @@
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -191,7 +190,7 @@
void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
if (BluetoothUtils.D) {
Log.d(TAG, "onProfileStateChanged: profile " + profile + ", device "
- + mDevice.getAlias() + ", newProfileState " + newProfileState);
+ + mDevice.getAnonymizedAddress() + ", newProfileState " + newProfileState);
}
if (mLocalAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF)
{
@@ -741,7 +740,7 @@
}
if (BluetoothUtils.D) {
- Log.d(TAG, "updating profiles for " + mDevice.getAlias());
+ Log.d(TAG, "updating profiles for " + mDevice.getAnonymizedAddress());
BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index 9afdd43c..f167721 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -43,6 +43,9 @@
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
+import java.util.Arrays;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
public class A2dpProfileTest {
@@ -179,7 +182,7 @@
BluetoothProfile.STATE_CONNECTED);
BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
- BluetoothCodecConfig[] configs = {config};
+ List<BluetoothCodecConfig> configs = Arrays.asList(config);
when(mBluetoothA2dp.getCodecStatus(mDevice)).thenReturn(status);
when(status.getCodecsSelectableCapabilities()).thenReturn(configs);
@@ -194,7 +197,7 @@
BluetoothProfile.STATE_CONNECTED);
BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
- BluetoothCodecConfig[] configs = {config};
+ List<BluetoothCodecConfig> configs = Arrays.asList(config);
when(mBluetoothA2dp.getCodecStatus(mDevice)).thenReturn(status);
when(status.getCodecsSelectableCapabilities()).thenReturn(configs);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 9cd7083..c30c742 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -98,6 +98,10 @@
private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config";
private static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings";
+ // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a
+ // fatal crash. Creating a backup with a different key will prevent Android 12 versions from
+ // restoring this data.
+ private static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2";
// Versioning of the state file. Increment this version
// number any time the set of state items is altered.
@@ -253,7 +257,7 @@
deviceSpecificInformation, data);
stateChecksums[STATE_SIM_SPECIFIC_SETTINGS] =
writeIfChanged(stateChecksums[STATE_SIM_SPECIFIC_SETTINGS],
- KEY_SIM_SPECIFIC_SETTINGS, simSpecificSettingsData, data);
+ KEY_SIM_SPECIFIC_SETTINGS_2, simSpecificSettingsData, data);
writeNewChecksums(stateChecksums, newState);
}
@@ -395,6 +399,9 @@
break;
case KEY_SIM_SPECIFIC_SETTINGS:
+ // Intentional fall through so that sim-specific backups from Android 12 will
+ // also be restored on newer Android versions.
+ case KEY_SIM_SPECIFIC_SETTINGS_2:
byte[] restoredSimSpecificSettings = new byte[size];
data.readEntityData(restoredSimSpecificSettings, 0, size);
restoreSimSpecificSettings(restoredSimSpecificSettings);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 073b4d0..6c6b0e8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1085,14 +1085,17 @@
Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE,
GlobalSettingsProto.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE);
- final long nitzUpdateToken = p.start(GlobalSettingsProto.NITZ_UPDATE);
+ final long nitzToken = p.start(GlobalSettingsProto.NITZ);
dumpSetting(s, p,
Settings.Global.NITZ_UPDATE_DIFF,
- GlobalSettingsProto.NitzUpdate.DIFF);
+ GlobalSettingsProto.Nitz.UPDATE_DIFF);
dumpSetting(s, p,
Settings.Global.NITZ_UPDATE_SPACING,
- GlobalSettingsProto.NitzUpdate.SPACING);
- p.end(nitzUpdateToken);
+ GlobalSettingsProto.Nitz.UPDATE_SPACING);
+ dumpSetting(s, p,
+ Settings.Global.NITZ_NETWORK_DISCONNECT_RETENTION,
+ GlobalSettingsProto.Nitz.NETWORK_DISCONNECT_RETENTION);
+ p.end(nitzToken);
final long notificationToken = p.start(GlobalSettingsProto.NOTIFICATION);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 3297937..773b068 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -388,6 +388,7 @@
Settings.Global.NETWORK_WATCHLIST_ENABLED,
Settings.Global.NEW_CONTACT_AGGREGATOR,
Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE,
+ Settings.Global.NITZ_NETWORK_DISCONNECT_RETENTION,
Settings.Global.NITZ_UPDATE_DIFF,
Settings.Global.NITZ_UPDATE_SPACING,
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 97cc948..87d50f2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -578,6 +578,9 @@
<!-- Permission required for CTS test - SettingsMultiPaneDeepLinkTest -->
<uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK" />
+ <!-- Permission required for ATS test - CarDevicePolicyManagerTest -->
+ <uses-permission android:name="android.permission.LOCK_DEVICE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/tests/AndroidTest.xml b/packages/SystemUI/tests/AndroidTest.xml
index fc353a1..5ffd300 100644
--- a/packages/SystemUI/tests/AndroidTest.xml
+++ b/packages/SystemUI/tests/AndroidTest.xml
@@ -18,12 +18,17 @@
<option name="test-file-name" value="SystemUITests.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <option name="force-root" value="true" />
+ </target_preparer>
+
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="framework-base-presubmit" />
<option name="test-tag" value="SystemUITests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.systemui.tests" />
<option name="runner" value="android.testing.TestableInstrumentation" />
+ <option name="test-filter-dir" value="/data/data/com.android.systemui.tests" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/services/Android.bp b/services/Android.bp
index cc0fd98..e11b044 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -23,6 +23,36 @@
},
}
+// Opt-in config for optimizing and shrinking the services target using R8.
+// Enabled via `export SYSTEM_OPTIMIZE_JAVA=true`, or explicitly in Make via the
+// `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA` variable.
+// TODO(b/196084106): Enable optimizations by default after stabilizing and
+// building out retrace infrastructure.
+soong_config_module_type {
+ name: "system_optimized_java_defaults",
+ module_type: "java_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: ["SYSTEM_OPTIMIZE_JAVA"],
+ properties: ["optimize"],
+}
+
+system_optimized_java_defaults {
+ name: "services_java_defaults",
+ soong_config_variables: {
+ SYSTEM_OPTIMIZE_JAVA: {
+ optimize: {
+ enabled: true,
+ optimize: true,
+ shrink: true,
+ proguard_flags_files: ["proguard.flags"],
+ },
+ // Note: Optimizations are disabled by default if unspecified in
+ // the java_library rule.
+ conditions_default: {},
+ },
+ },
+}
+
filegroup {
name: "services-main-sources",
srcs: [
@@ -81,6 +111,7 @@
// ============================================================
java_library {
name: "services",
+ defaults: ["services_java_defaults"],
installable: true,
dex_preopt: {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 7d75b73..0aa50bd 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -407,7 +407,7 @@
@Override
public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
synchronized (mLock) {
- if (mSecurityPolicy.canPerformGestures(this)) {
+ if (mServiceInterface != null && mSecurityPolicy.canPerformGestures(this)) {
MotionEventInjector motionEventInjector =
mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
if (motionEventInjector != null
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 2103bcc..d65969c 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -111,6 +111,7 @@
"java/com/android/server/am/EventLogTags.logtags",
"java/com/android/server/wm/EventLogTags.logtags",
"java/com/android/server/policy/EventLogTags.logtags",
+ ":services.connectivity-nsd-sources",
],
libs: [
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index b641377..71b463a 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -25,13 +25,14 @@
per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS
per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
+per-file **IpSec* = file:/services/core/java/com/android/server/net/OWNERS
+per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS
per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS
per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS
per-file *Storage* = file:/core/java/android/os/storage/OWNERS
per-file *TimeUpdate* = file:/core/java/android/app/timezone/OWNERS
per-file DynamicSystemService.java = file:/packages/DynamicSystemInstallationService/OWNERS
per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS
-per-file IpSecService.java = file:/services/core/java/com/android/server/net/OWNERS
per-file MmsServiceBroker.java = file:/telephony/OWNERS
per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS
per-file PackageWatchdog.java, RescueParty.java = file:/services/core/java/com/android/server/rollback/OWNERS
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 59bbb0d..32f6496 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1230,7 +1230,7 @@
}
for (int i = 0; i < mVolumes.size(); i++) {
final VolumeInfo vol = mVolumes.valueAt(i);
- if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
+ if (vol.isVisibleForUser(userId) && vol.isMountedReadable()) {
final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
@@ -1558,13 +1558,13 @@
&& VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
} else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
}
@@ -1574,13 +1574,13 @@
&& vol.disk.isDefaultPrimary()) {
Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
}
// Adoptable public disks are visible to apps, since they meet
// public API requirement of being in a stable location.
if (vol.disk.isAdoptable()) {
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
}
vol.mountUserId = mCurrentUserId;
@@ -1591,7 +1591,9 @@
} else if (vol.type == VolumeInfo.TYPE_STUB) {
if (vol.disk.isStubVisible()) {
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
+ } else {
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_READ;
}
vol.mountUserId = mCurrentUserId;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
@@ -1738,7 +1740,7 @@
// started after this point will trigger additional
// user-specific broadcasts.
for (int userId : mSystemUnlockedUsers) {
- if (vol.isVisibleForRead(userId)) {
+ if (vol.isVisibleForUser(userId)) {
final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
false);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
@@ -3766,7 +3768,7 @@
if (forWrite) {
match = vol.isVisibleForWrite(userId);
} else {
- match = vol.isVisibleForRead(userId)
+ match = vol.isVisibleForUser(userId)
|| (includeInvisible && vol.getPath() != null);
}
if (!match) continue;
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index cb6e73a..3cc8e76 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -21,18 +21,16 @@
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.os.Build;
import android.os.Environment;
import android.os.SystemClock;
import android.os.Trace;
-import android.util.ArrayMap;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.ClassLoaderFactory;
+import com.android.internal.os.SystemServerClassLoaderFactory;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService.TargetUser;
import com.android.server.am.EventLogTags;
@@ -77,9 +75,6 @@
// Services that should receive lifecycle events.
private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
- // Map of paths to PathClassLoader, so we don't load the same path multiple times.
- private final ArrayMap<String, PathClassLoader> mLoadedPaths = new ArrayMap<>();
-
private int mCurrentPhase = -1;
private UserManagerInternal mUserManagerInternal;
@@ -119,16 +114,8 @@
* @return The service instance.
*/
public SystemService startServiceFromJar(String className, String path) {
- PathClassLoader pathClassLoader = mLoadedPaths.get(path);
- if (pathClassLoader == null) {
- // NB: the parent class loader should always be the system server class loader.
- // Changing it has implications that require discussion with the mainline team.
- pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader(
- path, null /* librarySearchPath */, null /* libraryPermittedPath */,
- this.getClass().getClassLoader(), Build.VERSION.SDK_INT,
- true /* isNamespaceShared */, null /* classLoaderName */);
- mLoadedPaths.put(path, pathClassLoader);
- }
+ PathClassLoader pathClassLoader = SystemServerClassLoaderFactory.getOrCreateClassLoader(
+ path, this.getClass().getClassLoader());
final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader);
return startService(serviceClass);
}
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index b068f86..0c990ec 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -141,7 +141,7 @@
* | or its properties
* v |
* +-----------------------------------------------------------------------+
- * | UnderlyingNetworkTracker |
+ * | UnderlyingNetworkController |
* | |
* | Manages lifecycle of underlying physical networks, filing requests to |
* | bring them up, and releasing them as they become no longer necessary |
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b77270f..6c84ca4 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -374,6 +374,16 @@
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
/**
+ * Native heap allocations in AppZygote process and its descendants will now have a
+ * non-zero tag in the most significant byte.
+ * @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
+ * Pointers</a>
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long NATIVE_HEAP_POINTER_TAGGING_APP_ZYGOTE = 207557677;
+
+ /**
* Enable asynchronous (ASYNC) memory tag checking in this process. This
* flag will only have an effect on hardware supporting the ARM Memory
* Tagging Extension (MTE).
@@ -1738,6 +1748,16 @@
return level;
}
+ private int decideTaggingLevelForAppZygote(ProcessRecord app) {
+ int level = decideTaggingLevel(app);
+ // TBI ("fake" pointer tagging) in AppZygote is controlled by a separate compat feature.
+ if (!mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING_APP_ZYGOTE, app.info)
+ && level == Zygote.MEMORY_TAG_LEVEL_TBI) {
+ level = Zygote.MEMORY_TAG_LEVEL_NONE;
+ }
+ return level;
+ }
+
private int decideGwpAsanLevel(ProcessRecord app) {
// Look at the process attribute first.
if (app.processInfo != null
@@ -2238,7 +2258,8 @@
// not the calling one.
appInfo.packageName = app.getHostingRecord().getDefiningPackageName();
appInfo.uid = uid;
- appZygote = new AppZygote(appInfo, uid, firstUid, lastUid);
+ int runtimeFlags = decideTaggingLevelForAppZygote(app);
+ appZygote = new AppZygote(appInfo, uid, firstUid, lastUid, runtimeFlags);
mAppZygotes.put(app.info.processName, uid, appZygote);
zygoteProcessList = new ArrayList<ProcessRecord>();
mAppZygoteProcesses.put(appZygote, zygoteProcessList);
diff --git a/services/core/java/com/android/server/audio/TEST_MAPPING b/services/core/java/com/android/server/audio/TEST_MAPPING
index 90246f8..5a6c6a5 100644
--- a/services/core/java/com/android/server/audio/TEST_MAPPING
+++ b/services/core/java/com/android/server/audio/TEST_MAPPING
@@ -1,13 +1,13 @@
{
"presubmit-large": [
{
- "name": "CtsMediaTestCases",
+ "name": "CtsMediaAudioTestCases",
"options": [
{
- "include-filter": "android.media.cts.AudioManagerTest"
+ "include-filter": "android.media.audio.cts.AudioManagerTest"
},
{
- "include-filter": "android.media.cts.AudioFocusTest"
+ "include-filter": "android.media.audio.cts.AudioFocusTest"
}
]
}
diff --git a/services/core/java/com/android/server/biometrics/OWNERS b/services/core/java/com/android/server/biometrics/OWNERS
index 4eac972..f05f403 100644
--- a/services/core/java/com/android/server/biometrics/OWNERS
+++ b/services/core/java/com/android/server/biometrics/OWNERS
@@ -6,3 +6,4 @@
ilyamaty@google.com
joshmccloskey@google.com
jbolinger@google.com
+graciecheng@google.com
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 6ea84ce..ee5bda3 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -171,25 +171,28 @@
}
private NetworkMetrics getMetricsForNetwork(long timeMs, int netId) {
- collectPendingMetricsSnapshot(timeMs);
NetworkMetrics metrics = mNetworkMetrics.get(netId);
- if (metrics == null) {
- // TODO: allow to change transport for a given netid.
- metrics = new NetworkMetrics(netId, getTransports(netId), mConnectTb);
+ final NetworkCapabilities nc = mCallback.getNetworkCapabilities(netId);
+ final long transports = (nc != null) ? BitUtils.packBits(nc.getTransportTypes()) : 0;
+ final boolean forceCollect =
+ (metrics != null && nc != null && metrics.transports != transports);
+ collectPendingMetricsSnapshot(timeMs, forceCollect);
+ if (metrics == null || forceCollect) {
+ metrics = new NetworkMetrics(netId, transports, mConnectTb);
mNetworkMetrics.put(netId, metrics);
}
return metrics;
}
private NetworkMetricsSnapshot[] getNetworkMetricsSnapshots() {
- collectPendingMetricsSnapshot(System.currentTimeMillis());
+ collectPendingMetricsSnapshot(System.currentTimeMillis(), false /* forceCollect */);
return mNetworkMetricsSnapshots.toArray();
}
- private void collectPendingMetricsSnapshot(long timeMs) {
+ private void collectPendingMetricsSnapshot(long timeMs, boolean forceCollect) {
// Detects time differences larger than the snapshot collection period.
// This is robust against clock jumps and long inactivity periods.
- if (Math.abs(timeMs - mLastSnapshot) <= METRICS_SNAPSHOT_SPAN_MS) {
+ if (!forceCollect && Math.abs(timeMs - mLastSnapshot) <= METRICS_SNAPSHOT_SPAN_MS) {
return;
}
mLastSnapshot = projectSnapshotTime(timeMs);
@@ -394,14 +397,6 @@
return list;
}
- private long getTransports(int netId) {
- final NetworkCapabilities nc = mCallback.getNetworkCapabilities(netId);
- if (nc == null) {
- return 0;
- }
- return BitUtils.packBits(nc.getTransportTypes());
- }
-
/** Helper class for buffering summaries of NetworkMetrics at regular time intervals */
static class NetworkMetricsSnapshot {
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index df1eb6d..d17dbde 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -322,8 +322,11 @@
gateway = InetAddresses.parseNumericAddress(in.readUTF());
}
// If the destination is a default IPv4 route, use the gateway
- // address unless already set.
- if (dest.getAddress() instanceof Inet4Address
+ // address unless already set. If there is no destination, assume
+ // it is default route and use the gateway address in all cases.
+ if (dest == null) {
+ gatewayAddress = gateway;
+ } else if (dest.getAddress() instanceof Inet4Address
&& dest.getPrefixLength() == 0 && gatewayAddress == null) {
gatewayAddress = gateway;
} else {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 654b17f..81106b1 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -39,6 +39,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.RingBuffer;
import com.android.server.am.ProcessList;
+import com.android.server.net.NetworkPolicyManagerService.UidBlockedState;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@@ -72,16 +73,6 @@
private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13;
private static final int EVENT_APP_IDLE_WL_CHANGED = 14;
- static final int NTWK_BLOCKED_POWER = 0;
- static final int NTWK_ALLOWED_NON_METERED = 1;
- static final int NTWK_BLOCKED_DENYLIST = 2;
- static final int NTWK_ALLOWED_ALLOWLIST = 3;
- static final int NTWK_ALLOWED_TMP_ALLOWLIST = 4;
- static final int NTWK_BLOCKED_BG_RESTRICT = 5;
- static final int NTWK_ALLOWED_DEFAULT = 6;
- static final int NTWK_ALLOWED_SYSTEM = 7;
- static final int NTWK_BLOCKED_RESTRICTED_MODE = 8;
-
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
private final LogBuffer mEventsBuffer = new LogBuffer(MAX_LOG_SIZE);
@@ -90,12 +81,13 @@
private final Object mLock = new Object();
- void networkBlocked(int uid, int reason) {
+ void networkBlocked(int uid, UidBlockedState uidBlockedState) {
synchronized (mLock) {
if (LOGD || uid == mDebugUid) {
- Slog.d(TAG, uid + " is " + getBlockedReason(reason));
+ Slog.d(TAG, "Blocked state of uid: " + uidBlockedState.toString());
}
- mNetworkBlockedBuffer.networkBlocked(uid, reason);
+ mNetworkBlockedBuffer.networkBlocked(uid, uidBlockedState.blockedReasons,
+ uidBlockedState.allowedReasons, uidBlockedState.effectiveBlockedReasons);
}
}
@@ -269,29 +261,6 @@
}
}
- private static String getBlockedReason(int reason) {
- switch (reason) {
- case NTWK_BLOCKED_POWER:
- return "blocked by power restrictions";
- case NTWK_ALLOWED_NON_METERED:
- return "allowed on unmetered network";
- case NTWK_BLOCKED_DENYLIST:
- return "denylisted on metered network";
- case NTWK_ALLOWED_ALLOWLIST:
- return "allowlisted on metered network";
- case NTWK_ALLOWED_TMP_ALLOWLIST:
- return "temporary allowlisted on metered network";
- case NTWK_BLOCKED_BG_RESTRICT:
- return "blocked when background is restricted";
- case NTWK_ALLOWED_DEFAULT:
- return "allowed by default";
- case NTWK_BLOCKED_RESTRICTED_MODE:
- return "blocked by restricted networking mode";
- default:
- return String.valueOf(reason);
- }
- }
-
private static String getPolicyChangedLog(int uid, int oldPolicy, int newPolicy) {
return "Policy for " + uid + " changed from "
+ NetworkPolicyManager.uidPoliciesToString(oldPolicy) + " to "
@@ -402,14 +371,17 @@
data.timeStamp = System.currentTimeMillis();
}
- public void networkBlocked(int uid, int reason) {
+ public void networkBlocked(int uid, int blockedReasons, int allowedReasons,
+ int effectiveBlockedReasons) {
final Data data = getNextSlot();
if (data == null) return;
data.reset();
data.type = EVENT_NETWORK_BLOCKED;
data.ifield1 = uid;
- data.ifield2 = reason;
+ data.ifield2 = blockedReasons;
+ data.ifield3 = allowedReasons;
+ data.ifield4 = effectiveBlockedReasons;
data.timeStamp = System.currentTimeMillis();
}
@@ -554,7 +526,8 @@
case EVENT_TYPE_GENERIC:
return data.sfield1;
case EVENT_NETWORK_BLOCKED:
- return data.ifield1 + "-" + getBlockedReason(data.ifield2);
+ return data.ifield1 + "-" + UidBlockedState.toString(
+ data.ifield2, data.ifield3, data.ifield4);
case EVENT_UID_STATE_CHANGED:
return data.ifield1 + ":" + ProcessList.makeProcStateString(data.ifield2)
+ ":" + ActivityManager.getCapabilitiesSummary(data.ifield3)
@@ -593,17 +566,24 @@
}
}
- public final static class Data {
- int type;
- long timeStamp;
+ /**
+ * Container class for all networkpolicy events data.
+ *
+ * Note: This class needs to be public for RingBuffer class to be able to create
+ * new instances of this.
+ */
+ public static final class Data {
+ public int type;
+ public long timeStamp;
- int ifield1;
- int ifield2;
- int ifield3;
- long lfield1;
- boolean bfield1;
- boolean bfield2;
- String sfield1;
+ public int ifield1;
+ public int ifield2;
+ public int ifield3;
+ public int ifield4;
+ public long lfield1;
+ public boolean bfield1;
+ public boolean bfield2;
+ public String sfield1;
public void reset(){
sfield1 = null;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 20687c6..5de5fd3 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -79,14 +79,10 @@
import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
-import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
-import static android.net.NetworkPolicyManager.MASK_RESTRICTED_MODE_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -135,15 +131,6 @@
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_ALLOWLIST;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_DEFAULT;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_NON_METERED;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_SYSTEM;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_ALLOWLIST;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_DENYLIST;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_RESTRICTED_MODE;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -518,8 +505,6 @@
/** Defined UID policies. */
@GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidPolicy = new SparseIntArray();
- /** Currently derived rules for each UID. */
- @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidRules = new SparseIntArray();
@GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
@@ -598,6 +583,10 @@
@GuardedBy("mUidRulesFirstLock")
private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>();
+ /** Objects used temporarily while computing the new blocked state for each uid. */
+ @GuardedBy("mUidRulesFirstLock")
+ private final SparseArray<UidBlockedState> mTmpUidBlockedState = new SparseArray<>();
+
/** Map from network ID to last observed meteredness state */
@GuardedBy("mNetworkPoliciesSecondLock")
private final SparseBooleanArray mNetworkMetered = new SparseBooleanArray();
@@ -3825,7 +3814,7 @@
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids);
- collectKeys(mUidRules, knownUids);
+ collectKeys(mUidBlockedState, knownUids);
fout.println("Status for all known UIDs:");
fout.increaseIndent();
@@ -3843,23 +3832,13 @@
fout.print(uidState.toString());
}
- final int uidRules = mUidRules.get(uid, RULE_NONE);
- fout.print(" rules=");
- fout.print(uidRulesToString(uidRules));
- fout.println();
- }
- fout.decreaseIndent();
-
- fout.println("Status for just UIDs with rules:");
- fout.increaseIndent();
- size = mUidRules.size();
- for (int i = 0; i < size; i++) {
- final int uid = mUidRules.keyAt(i);
- fout.print("UID=");
- fout.print(uid);
- final int uidRules = mUidRules.get(uid, RULE_NONE);
- fout.print(" rules=");
- fout.print(uidRulesToString(uidRules));
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (uidBlockedState == null) {
+ fout.print(" blocked_state={null}");
+ } else {
+ fout.print(" blocked_state=");
+ fout.print(uidBlockedState.toString());
+ }
fout.println();
}
fout.decreaseIndent();
@@ -4010,22 +3989,17 @@
void updateRestrictedModeAllowlistUL() {
mUidFirewallRestrictedModeRules.clear();
forEachUid("updateRestrictedModeAllowlist", uid -> {
- final int oldUidRule = mUidRules.get(uid);
- final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule);
- final boolean hasUidRuleChanged = oldUidRule != newUidRule;
- final int newFirewallRule = getRestrictedModeFirewallRule(newUidRule);
+ synchronized (mUidRulesFirstLock) {
+ final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(
+ uid);
+ final int newFirewallRule = getRestrictedModeFirewallRule(uidBlockedState);
- // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
- // non-default rules.
- if (newFirewallRule != FIREWALL_RULE_DEFAULT) {
- mUidFirewallRestrictedModeRules.append(uid, newFirewallRule);
+ // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
+ // non-default rules.
+ if (newFirewallRule != FIREWALL_RULE_DEFAULT) {
+ mUidFirewallRestrictedModeRules.append(uid, newFirewallRule);
+ }
}
-
- if (hasUidRuleChanged) {
- mUidRules.put(uid, newUidRule);
- mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
- }
- updateBlockedReasonsForRestrictedModeUL(uid);
});
if (mRestrictedNetworkingMode) {
// firewall rules only need to be set when this mode is being enabled.
@@ -4038,15 +4012,7 @@
@VisibleForTesting
@GuardedBy("mUidRulesFirstLock")
void updateRestrictedModeForUidUL(int uid) {
- final int oldUidRule = mUidRules.get(uid);
- final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule);
- final boolean hasUidRuleChanged = oldUidRule != newUidRule;
-
- if (hasUidRuleChanged) {
- mUidRules.put(uid, newUidRule);
- mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
- }
- updateBlockedReasonsForRestrictedModeUL(uid);
+ final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(uid);
// if restricted networking mode is on, and the app has an access exemption, the uid rule
// will not change, but the firewall rule will have to be updated.
@@ -4054,16 +4020,14 @@
// Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules.
// In this case, default firewall rules can also be added.
setUidFirewallRule(FIREWALL_CHAIN_RESTRICTED, uid,
- getRestrictedModeFirewallRule(newUidRule));
+ getRestrictedModeFirewallRule(uidBlockedState));
}
}
- private void updateBlockedReasonsForRestrictedModeUL(int uid) {
- UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- uidBlockedState = new UidBlockedState();
- mUidBlockedState.put(uid, uidBlockedState);
- }
+ @GuardedBy("mUidRulesFirstLock")
+ private UidBlockedState updateBlockedReasonsForRestrictedModeUL(int uid) {
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
if (mRestrictedNetworkingMode) {
uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
@@ -4077,23 +4041,16 @@
}
uidBlockedState.updateEffectiveBlockedReasons();
if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
- mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
- uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
- .sendToTarget();
+ postBlockedReasonsChangedMsg(uid,
+ uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons);
+
+ postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
}
+ return uidBlockedState;
}
- private int getNewRestrictedModeUidRule(int uid, int oldUidRule) {
- int newRule = oldUidRule;
- newRule &= ~MASK_RESTRICTED_MODE_NETWORKS;
- if (mRestrictedNetworkingMode && !hasRestrictedModeAccess(uid)) {
- newRule |= RULE_REJECT_RESTRICTED_MODE;
- }
- return newRule;
- }
-
- private static int getRestrictedModeFirewallRule(int uidRule) {
- if ((uidRule & RULE_REJECT_RESTRICTED_MODE) != 0) {
+ private static int getRestrictedModeFirewallRule(UidBlockedState uidBlockedState) {
+ if ((uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
// rejected in restricted mode, this is the default behavior.
return FIREWALL_RULE_DEFAULT;
} else {
@@ -4301,16 +4258,12 @@
if (!isUidValidForDenylistRulesUL(uid)) {
continue;
}
- int oldRules = mUidRules.get(uid);
- if (enableChain) {
- // Chain wasn't enabled before and the other power-related
- // chains are allowlists, so we can clear the
- // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
- // the effective rules result in blocking network access.
- oldRules &= MASK_METERED_NETWORKS;
- } else {
- // Skip if it had no restrictions to begin with
- if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ if (!enableChain && (uidBlockedState.blockedReasons & ~BLOCKED_METERED_REASON_MASK)
+ == BLOCKED_REASON_NONE) {
+ // Chain isn't enabled and the uid had no restrictions to begin with.
+ continue;
}
final boolean isUidIdle = !paroled && isUidIdle(uid);
if (isUidIdle && !mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid))
@@ -4320,13 +4273,7 @@
} else {
mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DEFAULT);
}
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules,
- isUidIdle);
- if (newUidRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newUidRules);
- }
+ updateRulesForPowerRestrictionsUL(uid, isUidIdle);
}
setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, blockedUids,
enableChain ? CHAIN_TOGGLE_ENABLE : CHAIN_TOGGLE_DISABLE);
@@ -4544,6 +4491,7 @@
mInternetPermissionMap.put(uid, hasPermission);
return hasPermission;
} catch (RemoteException e) {
+ // ignored; service lives in system_server
}
return true;
}
@@ -4554,7 +4502,7 @@
@GuardedBy("mUidRulesFirstLock")
private void onUidDeletedUL(int uid) {
// First cleanup in-memory state synchronously...
- mUidRules.delete(uid);
+ mUidBlockedState.delete(uid);
mUidPolicy.delete(uid);
mUidFirewallStandbyRules.delete(uid);
mUidFirewallDozableRules.delete(uid);
@@ -4640,7 +4588,7 @@
* permission, since there is no need to change the {@code iptables} rule if the app does not
* have permission to use the internet.
*
- * <p>The {@link #mUidRules} map is used to define the transtion of states of an UID.
+ * <p>The {@link #mUidBlockedState} map is used to define the transition of states of an UID.
*
*/
private void updateRulesForDataUsageRestrictionsUL(int uid) {
@@ -4655,6 +4603,7 @@
}
}
+ @GuardedBy("mUidRulesFirstLock")
private void updateRulesForDataUsageRestrictionsULInner(int uid) {
if (!isUidValidForAllowlistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
@@ -4662,38 +4611,17 @@
}
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
- final int oldUidRules = mUidRules.get(uid, RULE_NONE);
final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
- UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- uidBlockedState = new UidBlockedState();
- mUidBlockedState.put(uid, uidBlockedState);
- }
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+ mTmpUidBlockedState, uid);
+ previousUidBlockedState.copyFrom(uidBlockedState);
final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
- // copy oldUidRules and clear out METERED_NETWORKS rules.
- int newUidRules = oldUidRules & (~MASK_METERED_NETWORKS);
-
- // First step: define the new rule based on user restrictions and foreground state.
- if (isRestrictedByAdmin) {
- newUidRules |= RULE_REJECT_METERED;
- } else if (isForeground) {
- if (isDenied || (mRestrictBackground && !isAllowed)) {
- newUidRules |= RULE_TEMPORARY_ALLOW_METERED;
- } else if (isAllowed) {
- newUidRules |= RULE_ALLOW_METERED;
- }
- } else {
- if (isDenied) {
- newUidRules |= RULE_REJECT_METERED;
- } else if (mRestrictBackground && isAllowed) {
- newUidRules |= RULE_ALLOW_METERED;
- }
- }
-
int newBlockedReasons = BLOCKED_REASON_NONE;
int newAllowedReasons = ALLOWED_REASON_NONE;
newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0);
@@ -4704,16 +4632,48 @@
newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0);
newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0);
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+ final int oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
+ final int newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
+ postBlockedReasonsChangedMsg(uid,
+ newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
+
+ postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ }
+
+ // Note that the conditionals below are for avoiding unnecessary calls to netd.
+ // TODO: Measure the performance for doing a no-op call to netd so that we can
+ // remove the conditionals to simplify the logic below. We can also further reduce
+ // some calls to netd if they turn out to be costly.
+ final int denylistReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
+ | BLOCKED_METERED_REASON_USER_RESTRICTED;
+ if ((oldEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE
+ || (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE) {
+ setMeteredNetworkDenylist(uid,
+ (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE);
+ }
+ final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
+ | ALLOWED_METERED_REASON_USER_EXEMPTED;
+ final int oldAllowedReasons = previousUidBlockedState.allowedReasons;
+ if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
+ || (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
+ setMeteredNetworkAllowlist(uid,
+ (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
+ }
+
if (LOGV) {
Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+ ": isForeground=" +isForeground
+ ", isDenied=" + isDenied
+ ", isAllowed=" + isAllowed
+ ", isRestrictedByAdmin=" + isRestrictedByAdmin
- + ", oldRule=" + uidRulesToString(oldUidRules & MASK_METERED_NETWORKS)
- + ", newRule=" + uidRulesToString(newUidRules & MASK_METERED_NETWORKS)
- + ", newUidRules=" + uidRulesToString(newUidRules)
- + ", oldUidRules=" + uidRulesToString(oldUidRules)
+ + ", oldBlockedState=" + previousUidBlockedState.toString()
+ + ", newBlockedState="
+ ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK)
+ ", oldBlockedMeteredEffectiveReasons="
@@ -4722,84 +4682,11 @@
+ ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
uidBlockedState.allowedReasons & BLOCKED_METERED_REASON_MASK));
}
-
- if (newUidRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newUidRules);
- }
-
- // Second step: apply bw changes based on change of state.
- if (newUidRules != oldUidRules) {
- if (hasRule(newUidRules, RULE_TEMPORARY_ALLOW_METERED)) {
- // Temporarily allow foreground app, removing from denylist if necessary
- // (since bw_penalty_box prevails over bw_happy_box).
-
- setMeteredNetworkAllowlist(uid, true);
- // TODO: if statement below is used to avoid an unnecessary call to netd / iptables,
- // but ideally it should be just:
- // setMeteredNetworkDenylist(uid, isDenied);
- if (isDenied) {
- setMeteredNetworkDenylist(uid, false);
- }
- } else if (hasRule(oldUidRules, RULE_TEMPORARY_ALLOW_METERED)) {
- // Remove temporary exemption from app that is not on foreground anymore.
-
- // TODO: if statements below are used to avoid unnecessary calls to netd / iptables,
- // but ideally they should be just:
- // setMeteredNetworkAllowlist(uid, isAllowed);
- // setMeteredNetworkDenylist(uid, isDenied);
- if (!isAllowed) {
- setMeteredNetworkAllowlist(uid, false);
- }
- if (isDenied || isRestrictedByAdmin) {
- setMeteredNetworkDenylist(uid, true);
- }
- } else if (hasRule(newUidRules, RULE_REJECT_METERED)
- || hasRule(oldUidRules, RULE_REJECT_METERED)) {
- // Flip state because app was explicitly added or removed to denylist.
- setMeteredNetworkDenylist(uid, (isDenied || isRestrictedByAdmin));
- if (hasRule(oldUidRules, RULE_REJECT_METERED) && isAllowed) {
- // Since denial prevails over allowance, we need to handle the special case
- // where app is allowed and denied at the same time (although such
- // scenario should be blocked by the UI), then it is removed from the denylist.
- setMeteredNetworkAllowlist(uid, isAllowed);
- }
- } else if (hasRule(newUidRules, RULE_ALLOW_METERED)
- || hasRule(oldUidRules, RULE_ALLOW_METERED)) {
- // Flip state because app was explicitly added or removed to allowlist.
- setMeteredNetworkAllowlist(uid, isAllowed);
- } else {
- // All scenarios should have been covered above.
- Log.wtf(TAG, "Unexpected change of metered UID state for " + uid
- + ": foreground=" + isForeground
- + ", allowlisted=" + isAllowed
- + ", denylisted=" + isDenied
- + ", isRestrictedByAdmin=" + isRestrictedByAdmin
- + ", newRule=" + uidRulesToString(newUidRules)
- + ", oldRule=" + uidRulesToString(oldUidRules));
- }
-
- // Dispatch changed rule to existing listeners.
- mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
- }
-
- final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
- uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
- & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
- uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
- & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
- uidBlockedState.updateEffectiveBlockedReasons();
- if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
- mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
- uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
- .sendToTarget();
- }
}
/**
- * Updates the power-related part of the {@link #mUidRules} for a given map, and notify external
- * listeners in case of change.
+ * Updates the power-related part of the {@link #mUidBlockedState} for a given map, and
+ * notify external listeners in case of change.
* <p>
* There are 3 power-related rules that affects whether an app has background access on
* non-metered networks, and when the condition applies and the UID is not allowed for power
@@ -4810,23 +4697,15 @@
* <li>Battery Saver Mode is on: {@code fw_powersave} firewall chain.
* </ul>
* <p>
- * This method updates the power-related part of the {@link #mUidRules} for a given uid based on
- * these modes, the UID process state (foreground or not), and the UID allowlist state.
+ * This method updates the power-related part of the {@link #mUidBlockedState} for a given
+ * uid based on these modes, the UID process state (foreground or not), and the UID
+ * allowlist state.
* <p>
* <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
*/
@GuardedBy("mUidRulesFirstLock")
private void updateRulesForPowerRestrictionsUL(int uid) {
- final int oldUidRules = mUidRules.get(uid, RULE_NONE);
-
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules,
- isUidIdle(uid));
-
- if (newUidRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newUidRules);
- }
+ updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid));
}
/**
@@ -4835,56 +4714,37 @@
* @param uid the uid of the app to update rules for
* @param oldUidRules the current rules for the uid, in order to determine if there's a change
* @param isUidIdle whether uid is idle or not
- *
- * @return the new computed rules for the uid
*/
@GuardedBy("mUidRulesFirstLock")
- private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean isUidIdle) {
+ private void updateRulesForPowerRestrictionsUL(int uid, boolean isUidIdle) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
- "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
+ "updateRulesForPowerRestrictionsUL: " + uid + "/"
+ (isUidIdle ? "I" : "-"));
}
try {
- return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, isUidIdle);
+ updateRulesForPowerRestrictionsULInner(uid, isUidIdle);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
@GuardedBy("mUidRulesFirstLock")
- private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules,
- boolean isUidIdle) {
+ private void updateRulesForPowerRestrictionsULInner(int uid, boolean isUidIdle) {
if (!isUidValidForDenylistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
- return RULE_NONE;
+ return;
}
- final boolean restrictMode = isUidIdle || mRestrictPower || mDeviceIdleMode;
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
- // Copy existing uid rules and clear ALL_NETWORK rules.
- int newUidRules = oldUidRules & (~MASK_ALL_NETWORKS);
-
- UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- uidBlockedState = new UidBlockedState();
- mUidBlockedState.put(uid, uidBlockedState);
- }
-
- // First step: define the new rule based on user restrictions and foreground state.
-
- // NOTE: if statements below could be inlined, but it's easier to understand the logic
- // by considering the foreground and non-foreground states.
- if (isForeground) {
- if (restrictMode) {
- newUidRules |= RULE_ALLOW_ALL;
- }
- } else if (restrictMode) {
- newUidRules |= isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL;
- }
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+ mTmpUidBlockedState, uid);
+ previousUidBlockedState.copyFrom(uidBlockedState);
int newBlockedReasons = BLOCKED_REASON_NONE;
int newAllowedReasons = ALLOWED_REASON_NONE;
@@ -4899,6 +4759,22 @@
? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
+ newAllowedReasons |= (uidBlockedState.allowedReasons
+ & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
+
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+ if (previousUidBlockedState.effectiveBlockedReasons
+ != uidBlockedState.effectiveBlockedReasons) {
+ postBlockedReasonsChangedMsg(uid,
+ uidBlockedState.effectiveBlockedReasons,
+ previousUidBlockedState.effectiveBlockedReasons);
+
+ postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ }
if (LOGV) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
@@ -4907,43 +4783,9 @@
+ ", mDeviceIdleMode: " + mDeviceIdleMode
+ ", isForeground=" + isForeground
+ ", isWhitelisted=" + isWhitelisted
- + ", oldRule=" + uidRulesToString(oldUidRules & MASK_ALL_NETWORKS)
- + ", newRule=" + uidRulesToString(newUidRules & MASK_ALL_NETWORKS)
- + ", newUidRules=" + uidRulesToString(newUidRules)
- + ", oldUidRules=" + uidRulesToString(oldUidRules));
+ + ", oldUidBlockedState=" + previousUidBlockedState.toString()
+ + ", newUidBlockedState=" + uidBlockedState.toString());
}
-
- // Second step: notify listeners if state changed.
- if (newUidRules != oldUidRules) {
- if ((newUidRules & MASK_ALL_NETWORKS) == RULE_NONE || hasRule(newUidRules,
- RULE_ALLOW_ALL)) {
- if (LOGV) Log.v(TAG, "Allowing non-metered access for UID " + uid);
- } else if (hasRule(newUidRules, RULE_REJECT_ALL)) {
- if (LOGV) Log.v(TAG, "Rejecting non-metered access for UID " + uid);
- } else {
- // All scenarios should have been covered above
- Log.wtf(TAG, "Unexpected change of non-metered UID state for " + uid
- + ": foreground=" + isForeground
- + ", whitelisted=" + isWhitelisted
- + ", newRule=" + uidRulesToString(newUidRules)
- + ", oldRule=" + uidRulesToString(oldUidRules));
- }
- mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
- }
-
- final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
- uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
- & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
- uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
- & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
- uidBlockedState.updateEffectiveBlockedReasons();
- if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
- mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
- uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
- .sendToTarget();
- }
-
- return newUidRules;
}
private class NetPolicyAppIdleStateChangeListener extends AppIdleStateChangeListener {
@@ -4971,10 +4813,23 @@
}
}
+ private void postBlockedReasonsChangedMsg(int uid, int newEffectiveBlockedReasons,
+ int oldEffectiveBlockedReasons) {
+ mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+ newEffectiveBlockedReasons, oldEffectiveBlockedReasons)
+ .sendToTarget();
+ }
+
+ private void postUidRulesChangedMsg(int uid, int uidRules) {
+ mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules)
+ .sendToTarget();
+ }
+
private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
try {
listener.onUidRulesChanged(uid, uidRules);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -4983,6 +4838,7 @@
try {
listener.onMeteredIfacesChanged(meteredIfaces);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -4991,6 +4847,7 @@
try {
listener.onRestrictBackgroundChanged(restrictBackground);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -4999,6 +4856,7 @@
try {
listener.onUidPoliciesChanged(uid, uidPolicies);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -5007,6 +4865,7 @@
try {
listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -5015,6 +4874,7 @@
try {
listener.onSubscriptionPlansChanged(subId, plans);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -5023,6 +4883,7 @@
try {
listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -5033,6 +4894,10 @@
case MSG_RULES_CHANGED: {
final int uid = msg.arg1;
final int uidRules = msg.arg2;
+ if (LOGV) {
+ Slog.v(TAG, "Dispatching rules=" + uidRulesToString(uidRules)
+ + " for uid=" + uid);
+ }
final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) {
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
@@ -5605,7 +5470,7 @@
}
}
- private static void collectKeys(SparseArray<UidState> source, SparseBooleanArray target) {
+ private static <T> void collectKeys(SparseArray<T> source, SparseBooleanArray target) {
final int size = source.size();
for (int i = 0; i < size; i++) {
target.put(source.keyAt(i), true);
@@ -5653,90 +5518,38 @@
final long startTime = mStatLogger.getTime();
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
- final int uidRules;
- final boolean isBackgroundRestricted;
+ int blockedReasons;
synchronized (mUidRulesFirstLock) {
- uidRules = mUidRules.get(uid, RULE_NONE);
- isBackgroundRestricted = mRestrictBackground;
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ blockedReasons = uidBlockedState == null
+ ? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
+ if (!isNetworkMetered) {
+ blockedReasons &= ~BLOCKED_METERED_REASON_MASK;
+ }
+ mLogger.networkBlocked(uid, uidBlockedState);
}
- final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
- isBackgroundRestricted, mLogger);
mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime);
- return ret;
+ return blockedReasons != BLOCKED_REASON_NONE;
}
@Override
public boolean isUidRestrictedOnMeteredNetworks(int uid) {
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
- final int uidRules;
- final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) {
- uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
- isBackgroundRestricted = mRestrictBackground;
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ int blockedReasons = uidBlockedState == null
+ ? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
+ blockedReasons &= BLOCKED_METERED_REASON_MASK;
+ return blockedReasons != BLOCKED_REASON_NONE;
}
- // TODO(b/177490332): The logic here might not be correct because it doesn't consider
- // RULE_REJECT_METERED condition. And it could be replaced by
- // isUidNetworkingBlockedInternal().
- return isBackgroundRestricted
- && !hasRule(uidRules, RULE_ALLOW_METERED)
- && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
}
private static boolean isSystem(int uid) {
return uid < Process.FIRST_APPLICATION_UID;
}
- static boolean isUidNetworkingBlockedInternal(int uid, int uidRules, boolean isNetworkMetered,
- boolean isBackgroundRestricted, @Nullable NetworkPolicyLogger logger) {
- final int reason;
- // Networks are never blocked for system components
- if (isSystem(uid)) {
- reason = NTWK_ALLOWED_SYSTEM;
- } else if (hasRule(uidRules, RULE_REJECT_RESTRICTED_MODE)) {
- reason = NTWK_BLOCKED_RESTRICTED_MODE;
- } else if (hasRule(uidRules, RULE_REJECT_ALL)) {
- reason = NTWK_BLOCKED_POWER;
- } else if (!isNetworkMetered) {
- reason = NTWK_ALLOWED_NON_METERED;
- } else if (hasRule(uidRules, RULE_REJECT_METERED)) {
- reason = NTWK_BLOCKED_DENYLIST;
- } else if (hasRule(uidRules, RULE_ALLOW_METERED)) {
- reason = NTWK_ALLOWED_ALLOWLIST;
- } else if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
- reason = NTWK_ALLOWED_TMP_ALLOWLIST;
- } else if (isBackgroundRestricted) {
- reason = NTWK_BLOCKED_BG_RESTRICT;
- } else {
- reason = NTWK_ALLOWED_DEFAULT;
- }
-
- final boolean blocked;
- switch(reason) {
- case NTWK_ALLOWED_DEFAULT:
- case NTWK_ALLOWED_NON_METERED:
- case NTWK_ALLOWED_TMP_ALLOWLIST:
- case NTWK_ALLOWED_ALLOWLIST:
- case NTWK_ALLOWED_SYSTEM:
- blocked = false;
- break;
- case NTWK_BLOCKED_RESTRICTED_MODE:
- case NTWK_BLOCKED_POWER:
- case NTWK_BLOCKED_DENYLIST:
- case NTWK_BLOCKED_BG_RESTRICT:
- blocked = true;
- break;
- default:
- throw new IllegalArgumentException();
- }
- if (logger != null) {
- logger.networkBlocked(uid, reason);
- }
-
- return blocked;
- }
-
private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
@Override
@@ -5945,6 +5758,16 @@
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
}
+ private static UidBlockedState getOrCreateUidBlockedStateForUid(
+ SparseArray<UidBlockedState> uidBlockedStates, int uid) {
+ UidBlockedState uidBlockedState = uidBlockedStates.get(uid);
+ if (uidBlockedState == null) {
+ uidBlockedState = new UidBlockedState();
+ uidBlockedStates.put(uid, uidBlockedState);
+ }
+ return uidBlockedState;
+ }
+
@VisibleForTesting
static final class UidBlockedState {
public int blockedReasons;
@@ -6008,9 +5831,180 @@
}
return effectiveBlockedReasons;
}
+
+ @Override
+ public String toString() {
+ return toString(blockedReasons, allowedReasons, effectiveBlockedReasons);
+ }
+
+ public static String toString(int blockedReasons, int allowedReasons,
+ int effectiveBlockedReasons) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("{");
+ sb.append("blocked=").append(blockedReasonsToString(blockedReasons)).append(",");
+ sb.append("allowed=").append(allowedReasonsToString(allowedReasons)).append(",");
+ sb.append("effective=").append(blockedReasonsToString(effectiveBlockedReasons));
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private static final int[] BLOCKED_REASONS = {
+ BLOCKED_REASON_BATTERY_SAVER,
+ BLOCKED_REASON_DOZE,
+ BLOCKED_REASON_APP_STANDBY,
+ BLOCKED_REASON_RESTRICTED_MODE,
+ BLOCKED_METERED_REASON_DATA_SAVER,
+ BLOCKED_METERED_REASON_USER_RESTRICTED,
+ BLOCKED_METERED_REASON_ADMIN_DISABLED,
+ };
+
+ private static final int[] ALLOWED_REASONS = {
+ ALLOWED_REASON_SYSTEM,
+ ALLOWED_REASON_FOREGROUND,
+ ALLOWED_REASON_POWER_SAVE_ALLOWLIST,
+ ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST,
+ ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS,
+ ALLOWED_METERED_REASON_USER_EXEMPTED,
+ ALLOWED_METERED_REASON_SYSTEM,
+ ALLOWED_METERED_REASON_FOREGROUND,
+ };
+
+ private static String blockedReasonToString(int blockedReason) {
+ switch (blockedReason) {
+ case BLOCKED_REASON_NONE:
+ return "NONE";
+ case BLOCKED_REASON_BATTERY_SAVER:
+ return "BATTERY_SAVER";
+ case BLOCKED_REASON_DOZE:
+ return "DOZE";
+ case BLOCKED_REASON_APP_STANDBY:
+ return "APP_STANDBY";
+ case BLOCKED_REASON_RESTRICTED_MODE:
+ return "RESTRICTED_MODE";
+ case BLOCKED_METERED_REASON_DATA_SAVER:
+ return "DATA_SAVER";
+ case BLOCKED_METERED_REASON_USER_RESTRICTED:
+ return "METERED_USER_RESTRICTED";
+ case BLOCKED_METERED_REASON_ADMIN_DISABLED:
+ return "METERED_ADMIN_DISABLED";
+ default:
+ Slog.wtfStack(TAG, "Unknown blockedReason: " + blockedReason);
+ return String.valueOf(blockedReason);
+ }
+ }
+
+ private static String allowedReasonToString(int allowedReason) {
+ switch (allowedReason) {
+ case ALLOWED_REASON_NONE:
+ return "NONE";
+ case ALLOWED_REASON_SYSTEM:
+ return "SYSTEM";
+ case ALLOWED_REASON_FOREGROUND:
+ return "FOREGROUND";
+ case ALLOWED_REASON_POWER_SAVE_ALLOWLIST:
+ return "POWER_SAVE_ALLOWLIST";
+ case ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST:
+ return "POWER_SAVE_EXCEPT_IDLE_ALLOWLIST";
+ case ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS:
+ return "RESTRICTED_MODE_PERMISSIONS";
+ case ALLOWED_METERED_REASON_USER_EXEMPTED:
+ return "METERED_USER_EXEMPTED";
+ case ALLOWED_METERED_REASON_SYSTEM:
+ return "METERED_SYSTEM";
+ case ALLOWED_METERED_REASON_FOREGROUND:
+ return "METERED_FOREGROUND";
+ default:
+ Slog.wtfStack(TAG, "Unknown allowedReason: " + allowedReason);
+ return String.valueOf(allowedReason);
+ }
+ }
+
+ public static String blockedReasonsToString(int blockedReasons) {
+ if (blockedReasons == BLOCKED_REASON_NONE) {
+ return blockedReasonToString(BLOCKED_REASON_NONE);
+ }
+ final StringBuilder sb = new StringBuilder();
+ for (int reason : BLOCKED_REASONS) {
+ if ((blockedReasons & reason) != 0) {
+ sb.append(sb.length() == 0 ? "" : "|");
+ sb.append(blockedReasonToString(reason));
+ blockedReasons &= ~reason;
+ }
+ }
+ if (blockedReasons != 0) {
+ sb.append(sb.length() == 0 ? "" : "|");
+ sb.append(String.valueOf(blockedReasons));
+ Slog.wtfStack(TAG, "Unknown blockedReasons: " + blockedReasons);
+ }
+ return sb.toString();
+ }
+
+ public static String allowedReasonsToString(int allowedReasons) {
+ if (allowedReasons == ALLOWED_REASON_NONE) {
+ return allowedReasonToString(ALLOWED_REASON_NONE);
+ }
+ final StringBuilder sb = new StringBuilder();
+ for (int reason : ALLOWED_REASONS) {
+ if ((allowedReasons & reason) != 0) {
+ sb.append(sb.length() == 0 ? "" : "|");
+ sb.append(allowedReasonToString(reason));
+ allowedReasons &= ~reason;
+ }
+ }
+ if (allowedReasons != 0) {
+ sb.append(sb.length() == 0 ? "" : "|");
+ sb.append(String.valueOf(allowedReasons));
+ Slog.wtfStack(TAG, "Unknown allowedReasons: " + allowedReasons);
+ }
+ return sb.toString();
+ }
+
+ public void copyFrom(UidBlockedState uidBlockedState) {
+ blockedReasons = uidBlockedState.blockedReasons;
+ allowedReasons = uidBlockedState.allowedReasons;
+ effectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ }
+
+ public int deriveUidRules() {
+ int uidRule = RULE_NONE;
+ if ((effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
+ uidRule |= RULE_REJECT_RESTRICTED_MODE;
+ }
+
+ int powerBlockedReasons = BLOCKED_REASON_APP_STANDBY
+ | BLOCKED_REASON_DOZE
+ | BLOCKED_REASON_BATTERY_SAVER;
+ if ((effectiveBlockedReasons & powerBlockedReasons) != 0) {
+ uidRule |= RULE_REJECT_ALL;
+ } else if ((blockedReasons & powerBlockedReasons) != 0) {
+ uidRule |= RULE_ALLOW_ALL;
+ }
+
+ // UidRule doesn't include RestrictBackground (DataSaver) state, so not including in
+ // metered blocked reasons below.
+ int meteredBlockedReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
+ | BLOCKED_METERED_REASON_USER_RESTRICTED;
+ if ((effectiveBlockedReasons & meteredBlockedReasons) != 0) {
+ uidRule |= RULE_REJECT_METERED;
+ } else if ((blockedReasons & BLOCKED_METERED_REASON_USER_RESTRICTED) != 0
+ && (allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) {
+ uidRule |= RULE_TEMPORARY_ALLOW_METERED;
+ } else if ((blockedReasons & BLOCKED_METERED_REASON_DATA_SAVER) != 0) {
+ if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
+ uidRule |= RULE_ALLOW_ALL;
+ } else if ((allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) {
+ uidRule |= RULE_TEMPORARY_ALLOW_METERED;
+ }
+ }
+ if (LOGV) {
+ Slog.v(TAG, "uidBlockedState=" + this.toString()
+ + " -> uidRule=" + uidRulesToString(uidRule));
+ }
+ return uidRule;
+ }
}
- private class NotificationId {
+ private static class NotificationId {
private final String mTag;
private final int mId;
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index f4b72a1..c876d41 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -150,6 +150,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.BinderUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
@@ -2097,14 +2098,18 @@
@Override
public void notifyAlertReached() throws RemoteException {
- mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */);
+ // This binder object can only have been obtained by a process that holds
+ // NETWORK_STATS_PROVIDER. Thus, no additional permission check is required.
+ BinderUtils.withCleanCallingIdentity(() ->
+ mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */));
}
@Override
public void notifyWarningOrLimitReached() {
Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
- LocalServices.getService(NetworkPolicyManagerInternal.class)
- .onStatsProviderWarningOrLimitReached(mTag);
+ BinderUtils.withCleanCallingIdentity(() ->
+ LocalServices.getService(NetworkPolicyManagerInternal.class)
+ .onStatsProviderWarningOrLimitReached(mTag));
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1aa80a9..5b4084e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2438,6 +2438,15 @@
}
}
+ private String getApexPackageNameContainingPackage(String pkg) {
+ ApexManager apexManager = ApexManager.getInstance();
+ return apexManager.getActiveApexPackageNameContainingPackage(pkg);
+ }
+
+ private boolean isApexApp(String pkg) {
+ return getApexPackageNameContainingPackage(pkg) != null;
+ }
+
private int runGetPrivappPermissions() {
final String pkg = getNextArg();
if (pkg == null) {
@@ -2453,6 +2462,9 @@
} else if (isSystemExtApp(pkg)) {
privAppPermissions = SystemConfig.getInstance()
.getSystemExtPrivAppPermissions(pkg);
+ } else if (isApexApp(pkg)) {
+ privAppPermissions = SystemConfig.getInstance()
+ .getApexPrivAppPermissions(getApexPackageNameContainingPackage(pkg), pkg);
} else {
privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
}
@@ -2477,6 +2489,9 @@
} else if (isSystemExtApp(pkg)) {
privAppPermissions = SystemConfig.getInstance()
.getSystemExtPrivAppDenyPermissions(pkg);
+ } else if (isApexApp(pkg)) {
+ privAppPermissions = SystemConfig.getInstance()
+ .getApexPrivAppDenyPermissions(getApexPackageNameContainingPackage(pkg), pkg);
} else {
privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7b12709..f733a2e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3443,10 +3443,15 @@
return true;
}
final String permissionName = permission.getName();
- if (isInSystemConfigPrivAppPermissions(pkg, permissionName)) {
+ final ApexManager apexManager = ApexManager.getInstance();
+ final String containingApexPackageName =
+ apexManager.getActiveApexPackageNameContainingPackage(packageName);
+ if (isInSystemConfigPrivAppPermissions(pkg, permissionName,
+ containingApexPackageName)) {
return true;
}
- if (isInSystemConfigPrivAppDenyPermissions(pkg, permissionName)) {
+ if (isInSystemConfigPrivAppDenyPermissions(pkg, permissionName,
+ containingApexPackageName)) {
return false;
}
// Updated system apps do not need to be allowlisted
@@ -3463,9 +3468,6 @@
}
// Only enforce the allowlist on boot
if (!mSystemReady) {
- final ApexManager apexManager = ApexManager.getInstance();
- final String containingApexPackageName =
- apexManager.getActiveApexPackageNameContainingPackage(packageName);
final boolean isInUpdatedApex = containingApexPackageName != null
&& !apexManager.isFactory(apexManager.getPackageInfo(containingApexPackageName,
MATCH_ACTIVE_PACKAGE));
@@ -3489,7 +3491,7 @@
}
private boolean isInSystemConfigPrivAppPermissions(@NonNull AndroidPackage pkg,
- @NonNull String permission) {
+ @NonNull String permission, String containingApexPackageName) {
final SystemConfig systemConfig = SystemConfig.getInstance();
final Set<String> permissions;
if (pkg.isVendor()) {
@@ -3498,6 +3500,26 @@
permissions = systemConfig.getProductPrivAppPermissions(pkg.getPackageName());
} else if (pkg.isSystemExt()) {
permissions = systemConfig.getSystemExtPrivAppPermissions(pkg.getPackageName());
+ } else if (containingApexPackageName != null) {
+ final Set<String> privAppPermissions = systemConfig.getPrivAppPermissions(
+ pkg.getPackageName());
+ final Set<String> apexPermissions = systemConfig.getApexPrivAppPermissions(
+ containingApexPackageName, pkg.getPackageName());
+ if (privAppPermissions != null) {
+ // TODO(andreionea): Remove check as soon as all apk-in-apex
+ // permission allowlists are migrated.
+ Slog.w(TAG, "Package " + pkg.getPackageName() + " is an APK in APEX,"
+ + " but has permission allowlist on the system image. Please bundle the"
+ + " allowlist in the " + containingApexPackageName + " APEX instead.");
+ if (apexPermissions != null) {
+ permissions = new ArraySet<>(privAppPermissions);
+ permissions.addAll(apexPermissions);
+ } else {
+ permissions = privAppPermissions;
+ }
+ } else {
+ permissions = apexPermissions;
+ }
} else {
permissions = systemConfig.getPrivAppPermissions(pkg.getPackageName());
}
@@ -3505,7 +3527,7 @@
}
private boolean isInSystemConfigPrivAppDenyPermissions(@NonNull AndroidPackage pkg,
- @NonNull String permission) {
+ @NonNull String permission, String containingApexPackageName) {
final SystemConfig systemConfig = SystemConfig.getInstance();
final Set<String> permissions;
if (pkg.isVendor()) {
@@ -3514,6 +3536,9 @@
permissions = systemConfig.getProductPrivAppDenyPermissions(pkg.getPackageName());
} else if (pkg.isSystemExt()) {
permissions = systemConfig.getSystemExtPrivAppDenyPermissions(pkg.getPackageName());
+ } else if (containingApexPackageName != null) {
+ permissions = systemConfig.getApexPrivAppDenyPermissions(containingApexPackageName,
+ pkg.getPackageName());
} else {
permissions = systemConfig.getPrivAppDenyPermissions(pkg.getPackageName());
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 1c46ac8..8b80b4a 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -77,6 +77,7 @@
import android.os.PowerManager.WakeLock;
import android.os.Process;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.Slog;
@@ -87,9 +88,10 @@
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback;
+import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
import com.android.server.vcn.util.LogUtils;
import com.android.server.vcn.util.MtuUtils;
import com.android.server.vcn.util.OneWayBoolean;
@@ -201,7 +203,7 @@
private interface EventInfo {}
/**
- * Sent when there are changes to the underlying network (per the UnderlyingNetworkTracker).
+ * Sent when there are changes to the underlying network (per the UnderlyingNetworkController).
*
* <p>May indicate an entirely new underlying network, OR a change in network properties.
*
@@ -522,11 +524,14 @@
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
- @NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+ @NonNull private final UnderlyingNetworkController mUnderlyingNetworkController;
@NonNull private final VcnGatewayConnectionConfig mConnectionConfig;
@NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback;
@NonNull private final Dependencies mDeps;
- @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
+
+ @NonNull
+ private final VcnUnderlyingNetworkControllerCallback mUnderlyingNetworkControllerCallback;
+
private final boolean mIsMobileDataEnabled;
@NonNull private final IpSecManager mIpSecManager;
@@ -674,17 +679,18 @@
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
- mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback();
+ mUnderlyingNetworkControllerCallback = new VcnUnderlyingNetworkControllerCallback();
mWakeLock =
mDeps.newWakeLock(mVcnContext.getContext(), PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mUnderlyingNetworkTracker =
- mDeps.newUnderlyingNetworkTracker(
+ mUnderlyingNetworkController =
+ mDeps.newUnderlyingNetworkController(
mVcnContext,
+ mConnectionConfig,
subscriptionGroup,
mLastSnapshot,
- mUnderlyingNetworkTrackerCallback);
+ mUnderlyingNetworkControllerCallback);
mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class);
addState(mDisconnectedState);
@@ -748,7 +754,7 @@
cancelRetryTimeoutAlarm();
cancelSafeModeAlarm();
- mUnderlyingNetworkTracker.teardown();
+ mUnderlyingNetworkController.teardown();
mGatewayStatusCallback.onQuit();
}
@@ -764,12 +770,13 @@
mVcnContext.ensureRunningOnLooperThread();
mLastSnapshot = snapshot;
- mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot);
+ mUnderlyingNetworkController.updateSubscriptionSnapshot(mLastSnapshot);
sendMessageAndAcquireWakeLock(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL);
}
- private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
+ private class VcnUnderlyingNetworkControllerCallback
+ implements UnderlyingNetworkControllerCallback {
@Override
public void onSelectedUnderlyingNetworkChanged(
@Nullable UnderlyingNetworkRecord underlying) {
@@ -783,8 +790,19 @@
// TODO(b/179091925): Move the delayed-message handling to BaseState
// If underlying is null, all underlying networks have been lost. Disconnect VCN after a
- // timeout.
+ // timeout (or immediately if in airplane mode, since the device user has indicated that
+ // the radios should all be turned off).
if (underlying == null) {
+ if (mDeps.isAirplaneModeOn(mVcnContext)) {
+ sendMessageAndAcquireWakeLock(
+ EVENT_UNDERLYING_NETWORK_CHANGED,
+ TOKEN_ALL,
+ new EventUnderlyingNetworkChangedInfo(null));
+ sendDisconnectRequestedAndAcquireWakelock(
+ DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */);
+ return;
+ }
+
setDisconnectRequestAlarm();
} else {
// Received a new Network so any previous alarm is irrelevant - cancel + clear it,
@@ -2264,7 +2282,7 @@
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
pw.println();
- mUnderlyingNetworkTracker.dump(pw);
+ mUnderlyingNetworkController.dump(pw);
pw.println();
pw.decreaseIndent();
@@ -2276,8 +2294,8 @@
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
- UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
- return mUnderlyingNetworkTrackerCallback;
+ UnderlyingNetworkControllerCallback getUnderlyingNetworkControllerCallback() {
+ return mUnderlyingNetworkControllerCallback;
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -2356,17 +2374,15 @@
/** External dependencies used by VcnGatewayConnection, for injection in tests */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class Dependencies {
- /** Builds a new UnderlyingNetworkTracker. */
- public UnderlyingNetworkTracker newUnderlyingNetworkTracker(
+ /** Builds a new UnderlyingNetworkController. */
+ public UnderlyingNetworkController newUnderlyingNetworkController(
VcnContext vcnContext,
+ VcnGatewayConnectionConfig connectionConfig,
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkTrackerCallback callback) {
- return new UnderlyingNetworkTracker(
- vcnContext,
- subscriptionGroup,
- snapshot,
- callback);
+ UnderlyingNetworkControllerCallback callback) {
+ return new UnderlyingNetworkController(
+ vcnContext, connectionConfig, subscriptionGroup, snapshot, callback);
}
/** Builds a new IkeSession. */
@@ -2422,6 +2438,12 @@
validationStatusCallback);
}
+ /** Checks if airplane mode is enabled. */
+ public boolean isAirplaneModeOn(@NonNull VcnContext vcnContext) {
+ return Settings.Global.getInt(vcnContext.getContext().getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+ }
+
/** Gets the elapsed real time since boot, in millis. */
public long getElapsedRealTime() {
return SystemClock.elapsedRealtime();
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
new file mode 100644
index 0000000..4576957
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
@@ -0,0 +1,309 @@
+/*
+ * 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.vcn.routeselection;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY;
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
+
+import static com.android.server.VcnManagementService.LOCAL_LOG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.NetworkCapabilities;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.VcnCellUnderlyingNetworkPriority;
+import android.net.vcn.VcnManager;
+import android.net.vcn.VcnUnderlyingNetworkPriority;
+import android.net.vcn.VcnWifiUnderlyingNetworkPriority;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.VcnContext;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/** @hide */
+class NetworkPriorityClassifier {
+ @NonNull private static final String TAG = NetworkPriorityClassifier.class.getSimpleName();
+ /**
+ * Minimum signal strength for a WiFi network to be eligible for switching to
+ *
+ * <p>A network that satisfies this is eligible to become the selected underlying network with
+ * no additional conditions
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70;
+ /**
+ * Minimum signal strength to continue using a WiFi network
+ *
+ * <p>A network that satisfies the conditions may ONLY continue to be used if it is already
+ * selected as the underlying network. A WiFi network satisfying this condition, but NOT the
+ * prospective-network RSSI threshold CANNOT be switched to.
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74;
+
+ /** Priority for any other networks (including unvalidated, etc) */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int PRIORITY_ANY = Integer.MAX_VALUE;
+
+ /** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */
+ public static int calculatePriorityClass(
+ VcnContext vcnContext,
+ UnderlyingNetworkRecord networkRecord,
+ LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED
+
+ if (networkRecord.isBlocked) {
+ logWtf("Network blocked for System Server: " + networkRecord.network);
+ return PRIORITY_ANY;
+ }
+
+ if (snapshot == null) {
+ logWtf("Got null snapshot");
+ return PRIORITY_ANY;
+ }
+
+ int priorityIndex = 0;
+ for (VcnUnderlyingNetworkPriority nwPriority : underlyingNetworkPriorities) {
+ if (checkMatchesPriorityRule(
+ vcnContext,
+ nwPriority,
+ networkRecord,
+ subscriptionGroup,
+ snapshot,
+ currentlySelected,
+ carrierConfig)) {
+ return priorityIndex;
+ }
+ priorityIndex++;
+ }
+ return PRIORITY_ANY;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static boolean checkMatchesPriorityRule(
+ VcnContext vcnContext,
+ VcnUnderlyingNetworkPriority networkPriority,
+ UnderlyingNetworkRecord networkRecord,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ // TODO: Check Network Quality reported by metric monitors/probers.
+
+ final NetworkCapabilities caps = networkRecord.networkCapabilities;
+ if (!networkPriority.allowMetered() && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+ return false;
+ }
+
+ if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) {
+ return true;
+ }
+
+ if (networkPriority instanceof VcnWifiUnderlyingNetworkPriority) {
+ return checkMatchesWifiPriorityRule(
+ (VcnWifiUnderlyingNetworkPriority) networkPriority,
+ networkRecord,
+ currentlySelected,
+ carrierConfig);
+ }
+
+ if (networkPriority instanceof VcnCellUnderlyingNetworkPriority) {
+ return checkMatchesCellPriorityRule(
+ vcnContext,
+ (VcnCellUnderlyingNetworkPriority) networkPriority,
+ networkRecord,
+ subscriptionGroup,
+ snapshot);
+ }
+
+ logWtf(
+ "Got unknown VcnUnderlyingNetworkPriority class: "
+ + networkPriority.getClass().getSimpleName());
+ return false;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static boolean checkMatchesWifiPriorityRule(
+ VcnWifiUnderlyingNetworkPriority networkPriority,
+ UnderlyingNetworkRecord networkRecord,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ final NetworkCapabilities caps = networkRecord.networkCapabilities;
+
+ if (!caps.hasTransport(TRANSPORT_WIFI)) {
+ return false;
+ }
+
+ // TODO: Move the Network Quality check to the network metric monitor framework.
+ if (networkPriority.getNetworkQuality()
+ > getWifiQuality(networkRecord, currentlySelected, carrierConfig)) {
+ return false;
+ }
+
+ if (networkPriority.getSsid() != null && networkPriority.getSsid() != caps.getSsid()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static int getWifiQuality(
+ UnderlyingNetworkRecord networkRecord,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ final NetworkCapabilities caps = networkRecord.networkCapabilities;
+ final boolean isSelectedNetwork =
+ currentlySelected != null
+ && networkRecord.network.equals(currentlySelected.network);
+
+ if (isSelectedNetwork
+ && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) {
+ return NETWORK_QUALITY_OK;
+ }
+
+ if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) {
+ return NETWORK_QUALITY_OK;
+ }
+
+ return NETWORK_QUALITY_ANY;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static boolean checkMatchesCellPriorityRule(
+ VcnContext vcnContext,
+ VcnCellUnderlyingNetworkPriority networkPriority,
+ UnderlyingNetworkRecord networkRecord,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot) {
+ final NetworkCapabilities caps = networkRecord.networkCapabilities;
+
+ if (!caps.hasTransport(TRANSPORT_CELLULAR)) {
+ return false;
+ }
+
+ final TelephonyNetworkSpecifier telephonyNetworkSpecifier =
+ ((TelephonyNetworkSpecifier) caps.getNetworkSpecifier());
+ if (telephonyNetworkSpecifier == null) {
+ logWtf("Got null NetworkSpecifier");
+ return false;
+ }
+
+ final int subId = telephonyNetworkSpecifier.getSubscriptionId();
+ final TelephonyManager subIdSpecificTelephonyMgr =
+ vcnContext
+ .getContext()
+ .getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(subId);
+
+ if (!networkPriority.getAllowedOperatorPlmnIds().isEmpty()) {
+ final String plmnId = subIdSpecificTelephonyMgr.getNetworkOperator();
+ if (!networkPriority.getAllowedOperatorPlmnIds().contains(plmnId)) {
+ return false;
+ }
+ }
+
+ if (!networkPriority.getAllowedSpecificCarrierIds().isEmpty()) {
+ final int carrierId = subIdSpecificTelephonyMgr.getSimSpecificCarrierId();
+ if (!networkPriority.getAllowedSpecificCarrierIds().contains(carrierId)) {
+ return false;
+ }
+ }
+
+ if (!networkPriority.allowRoaming() && !caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
+ return false;
+ }
+
+ if (networkPriority.requireOpportunistic()) {
+ if (!isOpportunistic(snapshot, caps.getSubscriptionIds())) {
+ return false;
+ }
+
+ // If this carrier is the active data provider, ensure that opportunistic is only
+ // ever prioritized if it is also the active data subscription. This ensures that
+ // if an opportunistic subscription is still in the process of being switched to,
+ // or switched away from, the VCN does not attempt to continue using it against the
+ // decision made at the telephony layer. Failure to do so may result in the modem
+ // switching back and forth.
+ //
+ // Allow the following two cases:
+ // 1. Active subId is NOT in the group that this VCN is supporting
+ // 2. This opportunistic subscription is for the active subId
+ if (snapshot.getAllSubIdsInGroup(subscriptionGroup)
+ .contains(SubscriptionManager.getActiveDataSubscriptionId())
+ && !caps.getSubscriptionIds()
+ .contains(SubscriptionManager.getActiveDataSubscriptionId())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ static boolean isOpportunistic(
+ @NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) {
+ if (snapshot == null) {
+ logWtf("Got null snapshot");
+ return false;
+ }
+ for (int subId : subIds) {
+ if (snapshot.isOpportunistic(subId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) {
+ if (carrierConfig != null) {
+ return carrierConfig.getInt(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
+ WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT);
+ }
+ return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
+ }
+
+ static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) {
+ if (carrierConfig != null) {
+ return carrierConfig.getInt(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
+ WIFI_EXIT_RSSI_THRESHOLD_DEFAULT);
+ }
+ return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
+ }
+
+ private static void logWtf(String msg) {
+ Slog.wtf(TAG, msg);
+ LOCAL_LOG.log(TAG + " WTF: " + msg);
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
similarity index 60%
rename from services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
rename to services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
index 7ddd135..cd124ee 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package com.android.server.vcn;
+package com.android.server.vcn.routeselection;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import static com.android.server.VcnManagementService.LOCAL_LOG;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiEntryRssiThreshold;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiExitRssiThreshold;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.isOpportunistic;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,27 +32,25 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
-import android.net.vcn.VcnManager;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnUnderlyingNetworkPriority;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Slog;
-import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.VcnContext;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -61,68 +60,19 @@
/**
* Tracks a set of Networks underpinning a VcnGatewayConnection.
*
- * <p>A single UnderlyingNetworkTracker is built to serve a SINGLE VCN Gateway Connection, and MUST
- * be torn down with the VcnGatewayConnection in order to ensure underlying networks are allowed to
- * be reaped.
+ * <p>A single UnderlyingNetworkController is built to serve a SINGLE VCN Gateway Connection, and
+ * MUST be torn down with the VcnGatewayConnection in order to ensure underlying networks are
+ * allowed to be reaped.
*
* @hide
*/
-public class UnderlyingNetworkTracker {
- @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName();
-
- /**
- * Minimum signal strength for a WiFi network to be eligible for switching to
- *
- * <p>A network that satisfies this is eligible to become the selected underlying network with
- * no additional conditions
- */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70;
-
- /**
- * Minimum signal strength to continue using a WiFi network
- *
- * <p>A network that satisfies the conditions may ONLY continue to be used if it is already
- * selected as the underlying network. A WiFi network satisfying this condition, but NOT the
- * prospective-network RSSI threshold CANNOT be switched to.
- */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74;
-
- /** Priority for any cellular network for which the subscription is listed as opportunistic */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0;
-
- /** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_WIFI_IN_USE = 1;
-
- /** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_WIFI_PROSPECTIVE = 2;
-
- /** Priority for any standard macro cellular network */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_MACRO_CELLULAR = 3;
-
- /** Priority for any other networks (including unvalidated, etc) */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_ANY = Integer.MAX_VALUE;
-
- private static final SparseArray<String> PRIORITY_TO_STRING_MAP = new SparseArray<>();
-
- static {
- PRIORITY_TO_STRING_MAP.put(
- PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR");
- PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE");
- PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE");
- PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR");
- PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY");
- }
+public class UnderlyingNetworkController {
+ @NonNull private static final String TAG = UnderlyingNetworkController.class.getSimpleName();
@NonNull private final VcnContext mVcnContext;
+ @NonNull private final VcnGatewayConnectionConfig mConnectionConfig;
@NonNull private final ParcelUuid mSubscriptionGroup;
- @NonNull private final UnderlyingNetworkTrackerCallback mCb;
+ @NonNull private final UnderlyingNetworkControllerCallback mCb;
@NonNull private final Dependencies mDeps;
@NonNull private final Handler mHandler;
@NonNull private final ConnectivityManager mConnectivityManager;
@@ -142,26 +92,24 @@
@Nullable private UnderlyingNetworkRecord mCurrentRecord;
@Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
- public UnderlyingNetworkTracker(
+ public UnderlyingNetworkController(
@NonNull VcnContext vcnContext,
+ @NonNull VcnGatewayConnectionConfig connectionConfig,
@NonNull ParcelUuid subscriptionGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
- @NonNull UnderlyingNetworkTrackerCallback cb) {
- this(
- vcnContext,
- subscriptionGroup,
- snapshot,
- cb,
- new Dependencies());
+ @NonNull UnderlyingNetworkControllerCallback cb) {
+ this(vcnContext, connectionConfig, subscriptionGroup, snapshot, cb, new Dependencies());
}
- private UnderlyingNetworkTracker(
+ private UnderlyingNetworkController(
@NonNull VcnContext vcnContext,
+ @NonNull VcnGatewayConnectionConfig connectionConfig,
@NonNull ParcelUuid subscriptionGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
- @NonNull UnderlyingNetworkTrackerCallback cb,
+ @NonNull UnderlyingNetworkControllerCallback cb,
@NonNull Dependencies deps) {
mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
+ mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
mCb = Objects.requireNonNull(cb, "Missing cb");
@@ -271,8 +219,8 @@
* subscription group, while the VCN networks are excluded by virtue of not having subIds set on
* the VCN-exposed networks.
*
- * <p>If the VCN that this UnderlyingNetworkTracker belongs to is in test-mode, this will return
- * a NetworkRequest that only matches Test Networks.
+ * <p>If the VCN that this UnderlyingNetworkController belongs to is in test-mode, this will
+ * return a NetworkRequest that only matches Test Networks.
*/
private NetworkRequest getRouteSelectionRequest() {
if (mVcnContext.isInTestMode()) {
@@ -373,9 +321,9 @@
}
/**
- * Update this UnderlyingNetworkTracker's TelephonySubscriptionSnapshot.
+ * Update this UnderlyingNetworkController's TelephonySubscriptionSnapshot.
*
- * <p>Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkTracker to
+ * <p>Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkController to
* reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered
* or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change.
*/
@@ -410,7 +358,7 @@
private void reevaluateNetworks() {
if (mIsQuitting || mRouteSelectionCallback == null) {
- return; // UnderlyingNetworkTracker has quit.
+ return; // UnderlyingNetworkController has quit.
}
TreeSet<UnderlyingNetworkRecord> sorted =
@@ -424,22 +372,6 @@
mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord);
}
- private static boolean isOpportunistic(
- @NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) {
- if (snapshot == null) {
- logWtf("Got null snapshot");
- return false;
- }
-
- for (int subId : subIds) {
- if (snapshot.isOpportunistic(subId)) {
- return true;
- }
- }
-
- return false;
- }
-
/**
* NetworkBringupCallback is used to keep background, VCN-managed Networks from being reaped.
*
@@ -468,6 +400,8 @@
TreeSet<UnderlyingNetworkRecord> sorted =
new TreeSet<>(
UnderlyingNetworkRecord.getComparator(
+ mVcnContext,
+ mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
mSubscriptionGroup,
mLastSnapshot,
mCurrentRecord,
@@ -544,230 +478,6 @@
}
}
- private static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) {
- if (carrierConfig != null) {
- return carrierConfig.getInt(
- VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
- WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT);
- }
-
- return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
- }
-
- private static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) {
- if (carrierConfig != null) {
- return carrierConfig.getInt(
- VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
- WIFI_EXIT_RSSI_THRESHOLD_DEFAULT);
- }
-
- return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
- }
-
- /** A record of a single underlying network, caching relevant fields. */
- public static class UnderlyingNetworkRecord {
- @NonNull public final Network network;
- @NonNull public final NetworkCapabilities networkCapabilities;
- @NonNull public final LinkProperties linkProperties;
- public final boolean isBlocked;
-
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- UnderlyingNetworkRecord(
- @NonNull Network network,
- @NonNull NetworkCapabilities networkCapabilities,
- @NonNull LinkProperties linkProperties,
- boolean isBlocked) {
- this.network = network;
- this.networkCapabilities = networkCapabilities;
- this.linkProperties = linkProperties;
- this.isBlocked = isBlocked;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof UnderlyingNetworkRecord)) return false;
- final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o;
-
- return network.equals(that.network)
- && networkCapabilities.equals(that.networkCapabilities)
- && linkProperties.equals(that.linkProperties)
- && isBlocked == that.isBlocked;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
- }
-
- /**
- * Gives networks a priority class, based on the following priorities:
- *
- * <ol>
- * <li>Opportunistic cellular
- * <li>Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT
- * <li>Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT
- * <li>Macro cellular
- * <li>Any others
- * </ol>
- */
- private int calculatePriorityClass(
- ParcelUuid subscriptionGroup,
- TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
- final NetworkCapabilities caps = networkCapabilities;
-
- // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED
-
- if (isBlocked) {
- logWtf("Network blocked for System Server: " + network);
- return PRIORITY_ANY;
- }
-
- if (caps.hasTransport(TRANSPORT_CELLULAR)
- && isOpportunistic(snapshot, caps.getSubscriptionIds())) {
- // If this carrier is the active data provider, ensure that opportunistic is only
- // ever prioritized if it is also the active data subscription. This ensures that
- // if an opportunistic subscription is still in the process of being switched to,
- // or switched away from, the VCN does not attempt to continue using it against the
- // decision made at the telephony layer. Failure to do so may result in the modem
- // switching back and forth.
- //
- // Allow the following two cases:
- // 1. Active subId is NOT in the group that this VCN is supporting
- // 2. This opportunistic subscription is for the active subId
- if (!snapshot.getAllSubIdsInGroup(subscriptionGroup)
- .contains(SubscriptionManager.getActiveDataSubscriptionId())
- || caps.getSubscriptionIds()
- .contains(SubscriptionManager.getActiveDataSubscriptionId())) {
- return PRIORITY_OPPORTUNISTIC_CELLULAR;
- }
- }
-
- if (caps.hasTransport(TRANSPORT_WIFI)) {
- if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)
- && currentlySelected != null
- && network.equals(currentlySelected.network)) {
- return PRIORITY_WIFI_IN_USE;
- }
-
- if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) {
- return PRIORITY_WIFI_PROSPECTIVE;
- }
- }
-
- // Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might
- // be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be
- // the case if the Default Data SubId does not support certain services (eg voice
- // calling)
- if (caps.hasTransport(TRANSPORT_CELLULAR)
- && !isOpportunistic(snapshot, caps.getSubscriptionIds())) {
- return PRIORITY_MACRO_CELLULAR;
- }
-
- return PRIORITY_ANY;
- }
-
- private static Comparator<UnderlyingNetworkRecord> getComparator(
- ParcelUuid subscriptionGroup,
- TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
- return (left, right) -> {
- return Integer.compare(
- left.calculatePriorityClass(
- subscriptionGroup, snapshot, currentlySelected, carrierConfig),
- right.calculatePriorityClass(
- subscriptionGroup, snapshot, currentlySelected, carrierConfig));
- };
- }
-
- /** Dumps the state of this record for logging and debugging purposes. */
- private void dump(
- IndentingPrintWriter pw,
- ParcelUuid subscriptionGroup,
- TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
- pw.println("UnderlyingNetworkRecord:");
- pw.increaseIndent();
-
- final int priorityClass =
- calculatePriorityClass(
- subscriptionGroup, snapshot, currentlySelected, carrierConfig);
- pw.println(
- "Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " ("
- + priorityClass + ")");
- pw.println("mNetwork: " + network);
- pw.println("mNetworkCapabilities: " + networkCapabilities);
- pw.println("mLinkProperties: " + linkProperties);
-
- pw.decreaseIndent();
- }
-
- /** Builder to incrementally construct an UnderlyingNetworkRecord. */
- private static class Builder {
- @NonNull private final Network mNetwork;
-
- @Nullable private NetworkCapabilities mNetworkCapabilities;
- @Nullable private LinkProperties mLinkProperties;
- boolean mIsBlocked;
- boolean mWasIsBlockedSet;
-
- @Nullable private UnderlyingNetworkRecord mCached;
-
- private Builder(@NonNull Network network) {
- mNetwork = network;
- }
-
- @NonNull
- private Network getNetwork() {
- return mNetwork;
- }
-
- private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
- mNetworkCapabilities = networkCapabilities;
- mCached = null;
- }
-
- @Nullable
- private NetworkCapabilities getNetworkCapabilities() {
- return mNetworkCapabilities;
- }
-
- private void setLinkProperties(@NonNull LinkProperties linkProperties) {
- mLinkProperties = linkProperties;
- mCached = null;
- }
-
- private void setIsBlocked(boolean isBlocked) {
- mIsBlocked = isBlocked;
- mWasIsBlockedSet = true;
- mCached = null;
- }
-
- private boolean isValid() {
- return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
- }
-
- private UnderlyingNetworkRecord build() {
- if (!isValid()) {
- throw new IllegalArgumentException(
- "Called build before UnderlyingNetworkRecord was valid");
- }
-
- if (mCached == null) {
- mCached =
- new UnderlyingNetworkRecord(
- mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
- }
-
- return mCached;
- }
- }
- }
-
private static void logWtf(String msg) {
Slog.wtf(TAG, msg);
LOCAL_LOG.log(TAG + " WTF: " + msg);
@@ -780,7 +490,7 @@
/** Dumps the state of this record for logging and debugging purposes. */
public void dump(IndentingPrintWriter pw) {
- pw.println("UnderlyingNetworkTracker:");
+ pw.println("UnderlyingNetworkController:");
pw.increaseIndent();
pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig));
@@ -788,12 +498,31 @@
pw.println(
"Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network));
+ pw.println("VcnUnderlyingNetworkPriority list:");
+ pw.increaseIndent();
+ int index = 0;
+ for (VcnUnderlyingNetworkPriority priority :
+ mConnectionConfig.getVcnUnderlyingNetworkPriorities()) {
+ pw.println("Priority index: " + index);
+ priority.dump(pw);
+ index++;
+ }
+ pw.decreaseIndent();
+ pw.println();
+
pw.println("Underlying networks:");
pw.increaseIndent();
if (mRouteSelectionCallback != null) {
for (UnderlyingNetworkRecord record :
mRouteSelectionCallback.getSortedUnderlyingNetworks()) {
- record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig);
+ record.dump(
+ mVcnContext,
+ pw,
+ mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
+ mSubscriptionGroup,
+ mLastSnapshot,
+ mCurrentRecord,
+ mCarrierConfig);
}
}
pw.decreaseIndent();
@@ -811,7 +540,7 @@
}
/** Callbacks for being notified of the changes in, or to the selected underlying network. */
- public interface UnderlyingNetworkTrackerCallback {
+ public interface UnderlyingNetworkControllerCallback {
/**
* Fired when a new underlying network is selected, or properties have changed.
*
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
new file mode 100644
index 0000000..27ba854
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
@@ -0,0 +1,222 @@
+/*
+ * 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.vcn.routeselection;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.vcn.VcnUnderlyingNetworkPriority;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.VcnContext;
+
+import java.util.Comparator;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+
+/**
+ * A record of a single underlying network, caching relevant fields.
+ *
+ * @hide
+ */
+public class UnderlyingNetworkRecord {
+ @NonNull public final Network network;
+ @NonNull public final NetworkCapabilities networkCapabilities;
+ @NonNull public final LinkProperties linkProperties;
+ public final boolean isBlocked;
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public UnderlyingNetworkRecord(
+ @NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties,
+ boolean isBlocked) {
+ this.network = network;
+ this.networkCapabilities = networkCapabilities;
+ this.linkProperties = linkProperties;
+ this.isBlocked = isBlocked;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof UnderlyingNetworkRecord)) return false;
+ final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o;
+
+ return network.equals(that.network)
+ && networkCapabilities.equals(that.networkCapabilities)
+ && linkProperties.equals(that.linkProperties)
+ && isBlocked == that.isBlocked;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
+ }
+
+ static Comparator<UnderlyingNetworkRecord> getComparator(
+ VcnContext vcnContext,
+ LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ return (left, right) -> {
+ final int leftIndex =
+ NetworkPriorityClassifier.calculatePriorityClass(
+ vcnContext,
+ left,
+ underlyingNetworkPriorities,
+ subscriptionGroup,
+ snapshot,
+ currentlySelected,
+ carrierConfig);
+ final int rightIndex =
+ NetworkPriorityClassifier.calculatePriorityClass(
+ vcnContext,
+ right,
+ underlyingNetworkPriorities,
+ subscriptionGroup,
+ snapshot,
+ currentlySelected,
+ carrierConfig);
+
+ // In the case of networks in the same priority class, prioritize based on other
+ // criteria (eg. actively selected network, link metrics, etc)
+ if (leftIndex == rightIndex) {
+ // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord
+ // fall into the same priority class.
+ if (isSelected(left, currentlySelected)) {
+ return -1;
+ }
+ if (isSelected(left, currentlySelected)) {
+ return 1;
+ }
+ }
+ return Integer.compare(leftIndex, rightIndex);
+ };
+ }
+
+ private static boolean isSelected(
+ UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected) {
+ if (currentlySelected == null) {
+ return false;
+ }
+ if (currentlySelected.network == recordToCheck.network) {
+ return true;
+ }
+ return false;
+ }
+
+ /** Dumps the state of this record for logging and debugging purposes. */
+ void dump(
+ VcnContext vcnContext,
+ IndentingPrintWriter pw,
+ LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ pw.println("UnderlyingNetworkRecord:");
+ pw.increaseIndent();
+
+ final int priorityIndex =
+ NetworkPriorityClassifier.calculatePriorityClass(
+ vcnContext,
+ this,
+ underlyingNetworkPriorities,
+ subscriptionGroup,
+ snapshot,
+ currentlySelected,
+ carrierConfig);
+
+ pw.println("Priority index:" + priorityIndex);
+ pw.println("mNetwork: " + network);
+ pw.println("mNetworkCapabilities: " + networkCapabilities);
+ pw.println("mLinkProperties: " + linkProperties);
+
+ pw.decreaseIndent();
+ }
+
+ /** Builder to incrementally construct an UnderlyingNetworkRecord. */
+ static class Builder {
+ @NonNull private final Network mNetwork;
+
+ @Nullable private NetworkCapabilities mNetworkCapabilities;
+ @Nullable private LinkProperties mLinkProperties;
+ boolean mIsBlocked;
+ boolean mWasIsBlockedSet;
+
+ @Nullable private UnderlyingNetworkRecord mCached;
+
+ Builder(@NonNull Network network) {
+ mNetwork = network;
+ }
+
+ @NonNull
+ Network getNetwork() {
+ return mNetwork;
+ }
+
+ void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
+ mNetworkCapabilities = networkCapabilities;
+ mCached = null;
+ }
+
+ @Nullable
+ NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities;
+ }
+
+ void setLinkProperties(@NonNull LinkProperties linkProperties) {
+ mLinkProperties = linkProperties;
+ mCached = null;
+ }
+
+ void setIsBlocked(boolean isBlocked) {
+ mIsBlocked = isBlocked;
+ mWasIsBlockedSet = true;
+ mCached = null;
+ }
+
+ boolean isValid() {
+ return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
+ }
+
+ UnderlyingNetworkRecord build() {
+ if (!isValid()) {
+ throw new IllegalArgumentException(
+ "Called build before UnderlyingNetworkRecord was valid");
+ }
+
+ if (mCached == null) {
+ mCached =
+ new UnderlyingNetworkRecord(
+ mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
+ }
+
+ return mCached;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
index 5c1b5ff..1c675c2 100644
--- a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
+++ b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
@@ -46,6 +46,7 @@
private static final String PARCEL_UUID_KEY = "PARCEL_UUID";
private static final String BYTE_ARRAY_KEY = "BYTE_ARRAY_KEY";
private static final String INTEGER_KEY = "INTEGER_KEY";
+ private static final String STRING_KEY = "STRING_KEY";
/**
* Functional interface to convert an object of the specified type to a PersistableBundle.
@@ -91,6 +92,21 @@
return bundle.getInt(INTEGER_KEY);
};
+ /** Serializer to convert s String to a PersistableBundle. */
+ public static final Serializer<String> STRING_SERIALIZER =
+ (i) -> {
+ final PersistableBundle result = new PersistableBundle();
+ result.putString(STRING_KEY, i);
+ return result;
+ };
+
+ /** Deserializer to convert a PersistableBundle to a String. */
+ public static final Deserializer<String> STRING_DESERIALIZER =
+ (bundle) -> {
+ Objects.requireNonNull(bundle, "PersistableBundle is null");
+ return bundle.getString(STRING_KEY);
+ };
+
/**
* Converts a ParcelUuid to a PersistableBundle.
*
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 710a304..e7005da 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -85,6 +85,7 @@
header_libs: [
"bionic_libc_platform_headers",
+ "bpf_connectivity_headers",
],
}
diff --git a/services/proguard.flags b/services/proguard.flags
new file mode 100644
index 0000000..30dd6cf
--- /dev/null
+++ b/services/proguard.flags
@@ -0,0 +1,11 @@
+# TODO(b/196084106): Refine and optimize this configuration. Note that this
+# configuration is only used when `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA=true`.
+-keep,allowoptimization,allowaccessmodification class ** {
+ *;
+}
+
+# Various classes subclassed in ethernet-service (avoid marking final).
+-keep public class android.net.** { *; }
+
+# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing).
+-keep public class com.android.server.utils.Slogf { *; }
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/OWNERS b/services/tests/servicestests/src/com/android/server/biometrics/OWNERS
index 8765c9a..6a2192a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/biometrics/OWNERS
@@ -1,7 +1 @@
-set noparent
-
-kchyn@google.com
-jaggies@google.com
-curtislb@google.com
-ilyamaty@google.com
-joshmccloskey@google.com
+include /services/core/java/com/android/server/biometrics/OWNERS
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index d06fe45..2b855e9 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -822,6 +822,17 @@
"android.telecom.extra.AUDIO_CODEC_BANDWIDTH_KHZ";
/**
+ * Last known cell identity key to be used to fill geo location header in case of an emergency
+ * call. This entry will not be filled if call is not identified as an emergency call.
+ * {@link Connection}. Only provided to the {@link ConnectionService} for the purpose
+ * of placing an emergency call; will not be present in the {@link InCallService} layer.
+ * The {@link ConnectionService}'s implementation will be logged for fine location access
+ * when an outgoing call is placed in this case.
+ */
+ public static final String EXTRA_LAST_KNOWN_CELL_IDENTITY =
+ "android.telecom.extra.LAST_KNOWN_CELL_IDENTITY";
+
+ /**
* Boolean connection extra key used to indicate whether device to device communication is
* available for the current call.
* @hide
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 4d81b5e..fcc23a9 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -107,6 +107,26 @@
}
}
+
+ /**
+ * Check whether the caller (or self, if not processing an IPC) has non dangerous
+ * read phone state permission.
+ * @param context app context
+ * @param message detail message
+ * @return true if permission is granted, else false
+ */
+ public static boolean checkCallingOrSelfReadNonDangerousPhoneStateNoThrow(
+ Context context, String message) {
+ try {
+ context.enforcePermission(
+ Manifest.permission.READ_BASIC_PHONE_STATE,
+ Binder.getCallingPid(), Binder.getCallingUid(), message);
+ return true;
+ } catch (SecurityException se) {
+ return false;
+ }
+ }
+
/**
* Check whether the app with the given pid/uid can read phone state.
*
@@ -545,6 +565,17 @@
}
/**
+ * Check if the caller (or self, if not processing an IPC) has ACCESS_LAST_KNOWN_CELL_ID
+ * permission
+ *
+ * @return true if caller has ACCESS_LAST_KNOWN_CELL_ID permission else false.
+ */
+ public static boolean checkLastKnownCellIdAccessPermission(Context context) {
+ return context.checkCallingOrSelfPermission("android.permission.ACCESS_LAST_KNOWN_CELL_ID")
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
* Ensure the caller (or self, if not processing an IPC) has
* {@link android.Manifest.permission#READ_PHONE_STATE} or carrier privileges.
*
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a1d68b2..a2efc96 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1895,9 +1895,10 @@
* the IMEI/SV for GSM phones. Return null if the software version is
* not available.
* <p>
- * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}.
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
@Nullable
public String getDeviceSoftwareVersion() {
return getDeviceSoftwareVersion(getSlotIndex());
@@ -2959,7 +2960,9 @@
* when opportunistic network is providing cellular internet connection to the user.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * or {@link android.Manifest.permission#READ_BASIC_PHONE_STATE
+ * READ_BASIC_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link #hasCarrierPrivileges}).
*
* @return the network type
*
@@ -2982,7 +2985,9 @@
* @see #NETWORK_TYPE_NR
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public @NetworkType int getDataNetworkType() {
return getDataNetworkType(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
}
@@ -3020,10 +3025,14 @@
* Returns the NETWORK_TYPE_xxxx for voice
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * or {@link android.Manifest.permission#READ_BASIC_PHONE_STATE
+ * READ_BASIC_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link #hasCarrierPrivileges}).
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public @NetworkType int getVoiceNetworkType() {
return getVoiceNetworkType(getSubId());
}
@@ -6587,12 +6596,7 @@
* @param AID Application id. See ETSI 102.221 and 101.220.
* @param p2 P2 parameter (described in ISO 7816-4).
* @return an IccOpenLogicalChannelResponse object.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openLogicalChannel(byte[], byte)}.
*/
- @Deprecated
public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) {
return iccOpenLogicalChannel(getSubId(), AID, p2);
}
@@ -6623,12 +6627,7 @@
* @param p2 P2 parameter (described in ISO 7816-4).
* @return an IccOpenLogicalChannelResponse object.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openLogicalChannel(byte[], byte)}.
*/
- @Deprecated
public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID, int p2) {
try {
ITelephony telephony = getITelephony();
@@ -6656,10 +6655,7 @@
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#close()}.
*/
- @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) {
@@ -6686,10 +6682,7 @@
* @param channel is the channel id to be closed as returned by a successful
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#close()}.
*/
- @Deprecated
public boolean iccCloseLogicalChannel(int channel) {
return iccCloseLogicalChannel(getSubId(), channel);
}
@@ -6708,10 +6701,7 @@
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#close()}.
*/
- @Deprecated
public boolean iccCloseLogicalChannel(int subId, int channel) {
try {
ITelephony telephony = getITelephony();
@@ -6747,10 +6737,7 @@
* @return The APDU response from the ICC card with the status appended at the end, or null if
* there is an issue connecting to the Telephony service.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
@Nullable
@@ -6788,10 +6775,7 @@
* @param data Data to be sent with the APDU.
* @return The APDU response from the ICC card with the status appended at
* the end.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String iccTransmitApduLogicalChannel(int channel, int cla,
int instruction, int p1, int p2, int p3, String data) {
return iccTransmitApduLogicalChannel(getSubId(), channel, cla,
@@ -6820,10 +6804,7 @@
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String iccTransmitApduLogicalChannel(int subId, int channel, int cla,
int instruction, int p1, int p2, int p3, String data) {
try {
@@ -6859,13 +6840,7 @@
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
@NonNull
@@ -6901,13 +6876,7 @@
* @param data Data to be sent with the APDU.
* @return The APDU response from the ICC card with the status appended at
* the end.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String iccTransmitApduBasicChannel(int cla,
int instruction, int p1, int p2, int p3, String data) {
return iccTransmitApduBasicChannel(getSubId(), cla,
@@ -6934,13 +6903,7 @@
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String iccTransmitApduBasicChannel(int subId, int cla,
int instruction, int p1, int p2, int p3, String data) {
try {
@@ -6968,13 +6931,7 @@
* @param p3 P3 value of the APDU command.
* @param filePath
* @return The APDU response.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
String filePath) {
return iccExchangeSimIO(getSubId(), fileID, command, p1, p2, p3, filePath);
@@ -6996,13 +6953,7 @@
* @param filePath
* @return The APDU response.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2,
int p3, String filePath) {
try {
@@ -7028,13 +6979,7 @@
* @return The APDU response from the ICC card in hexadecimal format
* with the last 4 bytes being the status word. If the command fails,
* returns an empty string.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String sendEnvelopeWithStatus(String content) {
return sendEnvelopeWithStatus(getSubId(), content);
}
@@ -7054,13 +6999,7 @@
* with the last 4 bytes being the status word. If the command fails,
* returns an empty string.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String sendEnvelopeWithStatus(int subId, String content) {
try {
ITelephony telephony = getITelephony();
@@ -9975,7 +9914,9 @@
*
* <p>Requires one of the following permissions:
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE},
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or that the calling app has carrier
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or
+ * {@link android.Manifest.permission#READ_BASIC_PHONE_STATE
+ * READ_BASIC_PHONE_STATE} or that the calling app has carrier
* privileges (see {@link #hasCarrierPrivileges}).
*
* <p>Note that this does not take into account any data restrictions that may be present on the
@@ -9986,7 +9927,8 @@
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
android.Manifest.permission.MODIFY_PHONE_STATE,
- android.Manifest.permission.READ_PHONE_STATE})
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public boolean isDataEnabled() {
try {
return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
@@ -10005,14 +9947,17 @@
*
* <p>Requires one of the following permissions:
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE},
- * {@link android.Manifest.permission#READ_PHONE_STATE} or that the calling app
+ * {@link android.Manifest.permission#READ_PHONE_STATE} or
+ * {@link android.Manifest.permission#READ_BASIC_PHONE_STATE
+ * READ_BASIC_PHONE_STATE} or that the calling app
* has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return {@code true} if the data roaming is enabled on the subscription, otherwise return
* {@code false}.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
- android.Manifest.permission.READ_PHONE_STATE})
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public boolean isDataRoamingEnabled() {
boolean isDataRoamingEnabled = false;
try {
@@ -12411,16 +12356,21 @@
* <p>If this object has been created with {@link #createForSubscriptionId}, applies
* to the given subId. Otherwise, applies to
* {@link SubscriptionManager#getDefaultDataSubscriptionId()}
- *
* @param reason the reason the data enable change is taking place
* @return whether data is enabled for a reason.
* <p>Requires Permission:
+ * The calling app has carrier privileges (see {@link #hasCarrierPrivileges}) or
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or
- * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} or
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_BASIC_PHONE_STATE}
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
- android.Manifest.permission.READ_PHONE_STATE})
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE
+ })
public boolean isDataEnabledForReason(@DataEnabledReason int reason) {
return isDataEnabledForReason(getSubId(), reason);
}
@@ -12555,14 +12505,11 @@
* <LI>And possibly others.</LI>
* </UL>
* @return {@code true} if the overall data connection is allowed; {@code false} if not.
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or
- * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} or
- * android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
android.Manifest.permission.READ_PHONE_STATE,
- android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public boolean isDataConnectionAllowed() {
boolean retVal = false;
try {
@@ -15858,4 +15805,31 @@
ex.rethrowAsRuntimeException();
}
}
+
+ /**
+ * Get last known cell identity.
+ * Require {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
+ * com.android.phone.permission.ACCESS_LAST_KNOWN_CELL_ID, otherwise throws SecurityException.
+ * If there is current registered network this value will be same as the registered cell
+ * identity. If the device goes out of service the previous cell identity is cached and
+ * will be returned. If the cache age of the Cell identity is more than 24 hours
+ * it will be cleared and null will be returned.
+ * @return last known cell identity {@CellIdentity}.
+ * @hide
+ */
+ @RequiresPermission(allOf = {Manifest.permission.ACCESS_FINE_LOCATION,
+ "com.android.phone.permission.ACCESS_LAST_KNOWN_CELL_ID"})
+ public @Nullable CellIdentity getLastKnownCellIdentity() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ return telephony.getLastKnownCellIdentity(getSubId(), getOpPackageName(),
+ getAttributionTag());
+ } catch (RemoteException ex) {
+ ex.rethrowAsRuntimeException();
+ }
+ return null;
+ }
}
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
index c00c741..c2c9497 100644
--- a/telephony/java/android/telephony/ims/DelegateRegistrationState.java
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
@@ -97,7 +97,24 @@
*/
public static final int DEREGISTERING_REASON_DESTROY_PENDING = 6;
- /** @hide */
+ /**
+ * This feature tag is deregistering because the PDN that the IMS registration is on
+ * is being torn down.
+ * <p>
+ * All open SIP Dialogs associated with this feature tag must be closed
+ * using {@link SipDelegateConnection#cleanupSession(String)} before this operation can proceed.
+ */
+ public static final int DEREGISTERING_REASON_LOSING_PDN = 7;
+
+ /**
+ * This feature tag is deregistering because of an unspecified reason.
+ * <p>
+ * All open SIP Dialogs associated with this feature tag must be closed
+ * using {@link SipDelegateConnection#cleanupSession(String)} before this operation can proceed.
+ */
+ public static final int DEREGISTERING_REASON_UNSPECIFIED = 8;
+
+/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "DEREGISTERED_REASON_", value = {
DEREGISTERED_REASON_UNKNOWN,
@@ -113,10 +130,13 @@
DEREGISTERING_REASON_PDN_CHANGE,
DEREGISTERING_REASON_PROVISIONING_CHANGE,
DEREGISTERING_REASON_FEATURE_TAGS_CHANGING,
- DEREGISTERING_REASON_DESTROY_PENDING
+ DEREGISTERING_REASON_DESTROY_PENDING,
+ DEREGISTERING_REASON_LOSING_PDN,
+ DEREGISTERING_REASON_UNSPECIFIED
})
public @interface DeregisteringReason {}
+ private ArraySet<String> mRegisteringTags = new ArraySet<>();
private ArraySet<String> mRegisteredTags = new ArraySet<>();
private final ArraySet<FeatureTagState> mDeregisteringTags = new ArraySet<>();
private final ArraySet<FeatureTagState> mDeregisteredTags = new ArraySet<>();
@@ -134,6 +154,20 @@
}
/**
+ * Add the set of feature tags that are associated with this SipDelegate and
+ * the IMS stack is actively trying to register on the carrier network.
+ *
+ * The feature tags will either move to the registered or deregistered state
+ * depending on the result of the registration.
+ * @param featureTags The IMS media feature tags that are in the progress of registering.
+ * @return The in-progress Builder instance for RegistrationState. ]
+ */
+ public @NonNull Builder addRegisteringFeatureTags(@NonNull Set<String> featureTags) {
+ mState.mRegisteringTags.addAll(featureTags);
+ return this;
+ }
+
+ /**
* Add a feature tag that is currently included in the current network IMS Registration.
* @param featureTag The IMS media feature tag included in the current IMS registration.
* @return The in-progress Builder instance for RegistrationState.
@@ -209,6 +243,17 @@
mRegisteredTags = (ArraySet<String>) source.readArraySet(null);
readStateFromParcel(source, mDeregisteringTags);
readStateFromParcel(source, mDeregisteredTags);
+ mRegisteringTags = (ArraySet<String>) source.readArraySet(null);
+ }
+
+ /**
+ * Get the feature tags that are associated with this SipDelegate that the IMS stack is actively
+ * trying to register on the carrier network.
+ * @return A Set of feature tags associated with this SipDelegate that the IMS service is
+ * currently trying to register on the carrier network.
+ */
+ public @NonNull Set<String> getRegisteringFeatureTags() {
+ return new ArraySet<>(mRegisteringTags);
}
/**
@@ -286,6 +331,7 @@
dest.writeArraySet(mRegisteredTags);
writeStateToParcel(dest, mDeregisteringTags);
writeStateToParcel(dest, mDeregisteredTags);
+ dest.writeArraySet(mRegisteringTags);
}
private void writeStateToParcel(Parcel dest, Set<FeatureTagState> state) {
@@ -311,19 +357,22 @@
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DelegateRegistrationState that = (DelegateRegistrationState) o;
- return mRegisteredTags.equals(that.mRegisteredTags)
+ return mRegisteringTags.equals(that.mRegisteringTags)
+ && mRegisteredTags.equals(that.mRegisteredTags)
&& mDeregisteringTags.equals(that.mDeregisteringTags)
&& mDeregisteredTags.equals(that.mDeregisteredTags);
}
@Override
public int hashCode() {
- return Objects.hash(mRegisteredTags, mDeregisteringTags, mDeregisteredTags);
+ return Objects.hash(mRegisteringTags, mRegisteredTags,
+ mDeregisteringTags, mDeregisteredTags);
}
@Override
public String toString() {
return "DelegateRegistrationState{ registered={" + mRegisteredTags
+ + "}, registering={" + mRegisteringTags
+ "}, deregistering={" + mDeregisteringTags + "}, deregistered={"
+ mDeregisteredTags + "}}";
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 6b33a68..2df5f53 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2509,4 +2509,13 @@
* Unregister an IMS connection state callback
*/
void unregisterImsStateCallback(in IImsStateCallback cb);
+
+ /**
+ * return last known cell identity
+ * @param subId user preferred subId.
+ * @param callingPackage the name of the package making the call.
+ * @param callingFeatureId The feature in the package.
+ */
+ CellIdentity getLastKnownCellIdentity(int subId, String callingPackage,
+ String callingFeatureId);
}
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 0bb6198..22320fd 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -27,9 +27,8 @@
java_sdk_library {
name: "android.test.mock",
-
- srcs: [
- ":android-test-mock-sources",
+ srcs: [":android-test-mock-sources"],
+ api_srcs: [
// Note: Below are NOT APIs of this library. We only take APIs under
// the android.test.mock package. They however provide private APIs that
// android.test.mock APIs references to. We need to have the classes in
@@ -44,15 +43,9 @@
"app-compat-annotations",
"unsupportedappusage",
],
-
api_packages: [
"android.test.mock",
],
- // Only include android.test.mock.* classes. Jarjar rules below removes
- // classes in other packages like android.content. In order to keep the
- // list up-to-date, permitted_packages ensures that the library contains
- // clases under android.test.mock after the jarjar rules are applied.
- jarjar_rules: "jarjar-rules.txt",
permitted_packages: [
"android.test.mock",
],
diff --git a/test-mock/jarjar-rules.txt b/test-mock/jarjar-rules.txt
deleted file mode 100644
index 4420a44..0000000
--- a/test-mock/jarjar-rules.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-zap android.accounts.**
-zap android.app.**
-zap android.content.**
-zap android.database.**
-zap android.os.**
-zap android.util.**
-zap android.view.**
diff --git a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java
new file mode 100644
index 0000000..476be44
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.vcn;
+
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY;
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class VcnCellUnderlyingNetworkPriorityTest {
+ private static final Set<String> ALLOWED_PLMN_IDS = new HashSet<>();
+ private static final Set<Integer> ALLOWED_CARRIER_IDS = new HashSet<>();
+
+ // Package private for use in VcnGatewayConnectionConfigTest
+ static VcnCellUnderlyingNetworkPriority getTestNetworkPriority() {
+ return new VcnCellUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setAllowedOperatorPlmnIds(ALLOWED_PLMN_IDS)
+ .setAllowedSpecificCarrierIds(ALLOWED_CARRIER_IDS)
+ .setAllowRoaming(true /* allowRoaming */)
+ .setRequireOpportunistic(true /* requireOpportunistic */)
+ .build();
+ }
+
+ @Test
+ public void testBuilderAndGetters() {
+ final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority();
+ assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality());
+ assertTrue(networkPriority.allowMetered());
+ assertEquals(ALLOWED_PLMN_IDS, networkPriority.getAllowedOperatorPlmnIds());
+ assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getAllowedSpecificCarrierIds());
+ assertTrue(networkPriority.allowRoaming());
+ assertTrue(networkPriority.requireOpportunistic());
+ }
+
+ @Test
+ public void testBuilderAndGettersForDefaultValues() {
+ final VcnCellUnderlyingNetworkPriority networkPriority =
+ new VcnCellUnderlyingNetworkPriority.Builder().build();
+ assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality());
+ assertFalse(networkPriority.allowMetered());
+ assertEquals(new HashSet<String>(), networkPriority.getAllowedOperatorPlmnIds());
+ assertEquals(new HashSet<Integer>(), networkPriority.getAllowedSpecificCarrierIds());
+ assertFalse(networkPriority.allowRoaming());
+ assertFalse(networkPriority.requireOpportunistic());
+ }
+
+ @Test
+ public void testPersistableBundle() {
+ final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority();
+ assertEquals(
+ networkPriority,
+ VcnUnderlyingNetworkPriority.fromPersistableBundle(
+ networkPriority.toPersistableBundle()));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index dc338ae..377f526 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -17,6 +17,8 @@
package android.net.vcn;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.vcn.VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_PRIORITIES;
+import static android.net.vcn.VcnGatewayConnectionConfig.UNDERLYING_NETWORK_PRIORITIES_KEY;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -30,6 +32,7 @@
import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.vcn.persistablebundleutils.IkeSessionParamsUtilsTest;
import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest;
+import android.os.PersistableBundle;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +41,7 @@
import org.junit.runner.RunWith;
import java.util.Arrays;
+import java.util.LinkedHashSet;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
@@ -50,9 +54,17 @@
};
public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
+ private static final LinkedHashSet<VcnUnderlyingNetworkPriority> UNDERLYING_NETWORK_PRIORITIES =
+ new LinkedHashSet();
+
static {
Arrays.sort(EXPOSED_CAPS);
Arrays.sort(UNDERLYING_CAPS);
+
+ UNDERLYING_NETWORK_PRIORITIES.add(
+ VcnCellUnderlyingNetworkPriorityTest.getTestNetworkPriority());
+ UNDERLYING_NETWORK_PRIORITIES.add(
+ VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority());
}
public static final long[] RETRY_INTERVALS_MS =
@@ -82,7 +94,10 @@
// Public for use in VcnGatewayConnectionTest
public static VcnGatewayConnectionConfig buildTestConfig() {
- return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
+ final VcnGatewayConnectionConfig.Builder builder =
+ newBuilder().setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_PRIORITIES);
+
+ return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS);
}
private static VcnGatewayConnectionConfig.Builder newBuilder() {
@@ -159,6 +174,15 @@
}
@Test
+ public void testBuilderRequiresNonNullNetworkPriorities() {
+ try {
+ newBuilder().setVcnUnderlyingNetworkPriorities(null);
+ fail("Expected exception due to invalid underlyingNetworkPriorities");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Test
public void testBuilderRequiresNonNullRetryInterval() {
try {
newBuilder().setRetryIntervalsMillis(null);
@@ -195,6 +219,7 @@
Arrays.sort(exposedCaps);
assertArrayEquals(EXPOSED_CAPS, exposedCaps);
+ assertEquals(UNDERLYING_NETWORK_PRIORITIES, config.getVcnUnderlyingNetworkPriorities());
assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams());
assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
@@ -208,6 +233,16 @@
assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
}
+ @Test
+ public void testParsePersistableBundleWithoutVcnUnderlyingNetworkPriorities() {
+ PersistableBundle configBundle = buildTestConfig().toPersistableBundle();
+ configBundle.putPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY, null);
+
+ final VcnGatewayConnectionConfig config = new VcnGatewayConnectionConfig(configBundle);
+ assertEquals(
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES, config.getVcnUnderlyingNetworkPriorities());
+ }
+
private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) {
final IkeSessionParams ikeParams =
IkeSessionParamsUtilsTest.createBuilderMinimum()
@@ -249,4 +284,40 @@
assertNotEquals(tunnelParams, anotherTunnelParams);
assertNotEquals(config, anotherConfig);
}
+
+ private static VcnGatewayConnectionConfig buildTestConfigWithVcnUnderlyingNetworkPriorities(
+ LinkedHashSet<VcnUnderlyingNetworkPriority> networkPriorities) {
+ return buildTestConfigWithExposedCaps(
+ new VcnGatewayConnectionConfig.Builder(
+ "buildTestConfigWithVcnUnderlyingNetworkPriorities",
+ TUNNEL_CONNECTION_PARAMS)
+ .setVcnUnderlyingNetworkPriorities(networkPriorities),
+ EXPOSED_CAPS);
+ }
+
+ @Test
+ public void testVcnUnderlyingNetworkPrioritiesEquality() throws Exception {
+ final VcnGatewayConnectionConfig config =
+ buildTestConfigWithVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_PRIORITIES);
+
+ final LinkedHashSet<VcnUnderlyingNetworkPriority> networkPrioritiesEqual =
+ new LinkedHashSet();
+ networkPrioritiesEqual.add(VcnCellUnderlyingNetworkPriorityTest.getTestNetworkPriority());
+ networkPrioritiesEqual.add(VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority());
+ final VcnGatewayConnectionConfig configEqual =
+ buildTestConfigWithVcnUnderlyingNetworkPriorities(networkPrioritiesEqual);
+
+ final LinkedHashSet<VcnUnderlyingNetworkPriority> networkPrioritiesNotEqual =
+ new LinkedHashSet();
+ networkPrioritiesNotEqual.add(
+ VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority());
+ final VcnGatewayConnectionConfig configNotEqual =
+ buildTestConfigWithVcnUnderlyingNetworkPriorities(networkPrioritiesNotEqual);
+
+ assertEquals(UNDERLYING_NETWORK_PRIORITIES, networkPrioritiesEqual);
+ assertEquals(config, configEqual);
+
+ assertNotEquals(UNDERLYING_NETWORK_PRIORITIES, networkPrioritiesNotEqual);
+ assertNotEquals(config, configNotEqual);
+ }
}
diff --git a/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java
new file mode 100644
index 0000000..dd272cb
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.vcn;
+
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY;
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+public class VcnWifiUnderlyingNetworkPriorityTest {
+ private static final String SSID = "TestWifi";
+ private static final int INVALID_NETWORK_QUALITY = -1;
+
+ // Package private for use in VcnGatewayConnectionConfigTest
+ static VcnWifiUnderlyingNetworkPriority getTestNetworkPriority() {
+ return new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setSsid(SSID)
+ .build();
+ }
+
+ @Test
+ public void testBuilderAndGetters() {
+ final VcnWifiUnderlyingNetworkPriority networkPriority = getTestNetworkPriority();
+ assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality());
+ assertTrue(networkPriority.allowMetered());
+ assertEquals(SSID, networkPriority.getSsid());
+ }
+
+ @Test
+ public void testBuilderAndGettersForDefaultValues() {
+ final VcnWifiUnderlyingNetworkPriority networkPriority =
+ new VcnWifiUnderlyingNetworkPriority.Builder().build();
+ assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality());
+ assertFalse(networkPriority.allowMetered());
+ assertNull(SSID, networkPriority.getSsid());
+ }
+
+ @Test
+ public void testBuildWithInvalidNetworkQuality() {
+ try {
+ new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(INVALID_NETWORK_QUALITY);
+ fail("Expected to fail due to the invalid network quality");
+ } catch (Exception expected) {
+ }
+ }
+
+ @Test
+ public void testPersistableBundle() {
+ final VcnWifiUnderlyingNetworkPriority networkPriority = getTestNetworkPriority();
+ assertEquals(
+ networkPriority,
+ VcnUnderlyingNetworkPriority.fromPersistableBundle(
+ networkPriority.toPersistableBundle()));
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 937f9dc..e547400 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -118,8 +118,10 @@
@Test
public void testNullNetworkDoesNotTriggerDisconnect() throws Exception {
+ doReturn(false).when(mDeps).isAirplaneModeOn(any());
+
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
mTestLooper.dispatchAll();
@@ -129,9 +131,22 @@
}
@Test
+ public void testNullNetworkAirplaneModeDisconnects() throws Exception {
+ doReturn(true).when(mDeps).isAirplaneModeOn(any());
+
+ mGatewayConnection
+ .getUnderlyingNetworkControllerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).kill();
+ }
+
+ @Test
public void testNewNetworkTriggersMigration() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
mTestLooper.dispatchAll();
@@ -143,7 +158,7 @@
@Test
public void testSameNetworkDoesNotTriggerMigration() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
mTestLooper.dispatchAll();
@@ -203,7 +218,7 @@
triggerChildOpened();
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
getChildSessionCallback()
.onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index d1f3a21..3c70759 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -64,7 +64,7 @@
@Test
public void testNullNetworkTriggersDisconnect() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
mTestLooper.dispatchAll();
@@ -76,7 +76,7 @@
@Test
public void testNewNetworkTriggersReconnect() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
mTestLooper.dispatchAll();
@@ -89,7 +89,7 @@
@Test
public void testSameNetworkDoesNotTriggerReconnect() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
mTestLooper.dispatchAll();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 2056eea..f3eb82f 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -78,7 +78,7 @@
@Test
public void testNetworkChangesTriggerStateTransitions() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
mTestLooper.dispatchAll();
@@ -89,7 +89,7 @@
@Test
public void testNullNetworkDoesNotTriggerStateTransition() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
mTestLooper.dispatchAll();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index 1c85979..6568cdd 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -58,7 +58,7 @@
@Test
public void testNewNetworkTriggerRetry() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
mTestLooper.dispatchAll();
@@ -72,7 +72,7 @@
@Test
public void testSameNetworkDoesNotTriggerRetry() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
mTestLooper.dispatchAll();
@@ -86,7 +86,7 @@
@Test
public void testNullNetworkTriggersDisconnect() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
mTestLooper.dispatchAll();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 2b0037e..b9dfda3 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -59,7 +59,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
import org.junit.Before;
import org.junit.Test;
@@ -238,14 +238,14 @@
}
@Test
- public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() {
+ public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkController() {
verifyWakeLockSetUp();
final TelephonySubscriptionSnapshot updatedSnapshot =
mock(TelephonySubscriptionSnapshot.class);
mGatewayConnection.updateSubscriptionSnapshot(updatedSnapshot);
- verify(mUnderlyingNetworkTracker).updateSubscriptionSnapshot(eq(updatedSnapshot));
+ verify(mUnderlyingNetworkController).updateSubscriptionSnapshot(eq(updatedSnapshot));
verifyWakeLockAcquired();
mTestLooper.dispatchAll();
@@ -256,13 +256,13 @@
@Test
public void testNonNullUnderlyingNetworkRecordUpdateCancelsAlarm() {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
verify(mDisconnectRequestAlarm).cancel();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 64d0bca..5628321 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -16,7 +16,6 @@
package com.android.server.vcn;
-import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
@@ -62,6 +61,8 @@
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController;
+import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
@@ -137,7 +138,7 @@
@NonNull protected final VcnGatewayConnectionConfig mConfig;
@NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback;
@NonNull protected final VcnGatewayConnection.Dependencies mDeps;
- @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+ @NonNull protected final UnderlyingNetworkController mUnderlyingNetworkController;
@NonNull protected final VcnWakeLock mWakeLock;
@NonNull protected final WakeupMessage mTeardownTimeoutAlarm;
@NonNull protected final WakeupMessage mDisconnectRequestAlarm;
@@ -158,7 +159,7 @@
mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class);
mDeps = mock(VcnGatewayConnection.Dependencies.class);
- mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
+ mUnderlyingNetworkController = mock(UnderlyingNetworkController.class);
mWakeLock = mock(VcnWakeLock.class);
mTeardownTimeoutAlarm = mock(WakeupMessage.class);
mDisconnectRequestAlarm = mock(WakeupMessage.class);
@@ -176,9 +177,9 @@
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
- doReturn(mUnderlyingNetworkTracker)
+ doReturn(mUnderlyingNetworkController)
.when(mDeps)
- .newUnderlyingNetworkTracker(any(), any(), any(), any());
+ .newUnderlyingNetworkController(any(), any(), any(), any(), any());
doReturn(mWakeLock)
.when(mDeps)
.newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
new file mode 100644
index 0000000..46a614f
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
@@ -0,0 +1,383 @@
+/*
+ * 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.vcn.routeselection;
+
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
+
+import static com.android.server.vcn.VcnTestUtils.setupSystemService;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.calculatePriorityClass;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule;
+import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.VcnCellUnderlyingNetworkPriority;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnManager;
+import android.net.vcn.VcnWifiUnderlyingNetworkPriority;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.os.test.TestLooper;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
+
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.VcnContext;
+import com.android.server.vcn.VcnNetworkProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Set;
+import java.util.UUID;
+
+public class NetworkPriorityClassifierTest {
+ private static final String SSID = "TestWifi";
+ private static final String SSID_OTHER = "TestWifiOther";
+ private static final String PLMN_ID = "123456";
+ private static final String PLMN_ID_OTHER = "234567";
+
+ private static final int SUB_ID = 1;
+ private static final int WIFI_RSSI = -60;
+ private static final int WIFI_RSSI_HIGH = -50;
+ private static final int WIFI_RSSI_LOW = -80;
+ private static final int CARRIER_ID = 1;
+ private static final int CARRIER_ID_OTHER = 2;
+
+ private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
+
+ private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES =
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setSignalStrength(WIFI_RSSI)
+ .setSsid(SSID)
+ .build();
+
+ private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER =
+ new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build();
+ private static final NetworkCapabilities CELL_NETWORK_CAPABILITIES =
+ new NetworkCapabilities.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .setSubscriptionIds(Set.of(SUB_ID))
+ .setNetworkSpecifier(TEL_NETWORK_SPECIFIER)
+ .build();
+
+ private static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface");
+
+ @Mock private Network mNetwork;
+ @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
+ @Mock private TelephonyManager mTelephonyManager;
+
+ private TestLooper mTestLooper;
+ private VcnContext mVcnContext;
+ private UnderlyingNetworkRecord mWifiNetworkRecord;
+ private UnderlyingNetworkRecord mCellNetworkRecord;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ final Context mockContext = mock(Context.class);
+ mTestLooper = new TestLooper();
+ mVcnContext =
+ spy(
+ new VcnContext(
+ mockContext,
+ mTestLooper.getLooper(),
+ mock(VcnNetworkProvider.class),
+ false /* isInTestMode */));
+ doNothing().when(mVcnContext).ensureRunningOnLooperThread();
+
+ mWifiNetworkRecord =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ WIFI_NETWORK_CAPABILITIES,
+ LINK_PROPERTIES,
+ false /* isBlocked */);
+
+ mCellNetworkRecord =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ CELL_NETWORK_CAPABILITIES,
+ LINK_PROPERTIES,
+ false /* isBlocked */);
+
+ setupSystemService(
+ mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
+ when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID);
+ when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID);
+ }
+
+ @Test
+ public void testMatchWithoutNotMeteredBit() {
+ final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority =
+ new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(false /* allowMetered */)
+ .build();
+
+ assertFalse(
+ checkMatchesPriorityRule(
+ mVcnContext,
+ wifiNetworkPriority,
+ mWifiNetworkRecord,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ null /* currentlySelecetd */,
+ null /* carrierConfig */));
+ }
+
+ private void verifyMatchWifi(
+ boolean isSelectedNetwork, PersistableBundle carrierConfig, boolean expectMatch) {
+ final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority =
+ new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .build();
+ final UnderlyingNetworkRecord selectedNetworkRecord =
+ isSelectedNetwork ? mWifiNetworkRecord : null;
+ assertEquals(
+ expectMatch,
+ checkMatchesWifiPriorityRule(
+ wifiNetworkPriority,
+ mWifiNetworkRecord,
+ selectedNetworkRecord,
+ carrierConfig));
+ }
+
+ @Test
+ public void testMatchSelectedWifi() {
+ verifyMatchWifi(
+ true /* isSelectedNetwork */, null /* carrierConfig */, true /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchSelectedWifiBelowRssiThreshold() {
+ final PersistableBundle carrierConfig = new PersistableBundle();
+ carrierConfig.putInt(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH);
+ carrierConfig.putInt(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH);
+
+ verifyMatchWifi(true /* isSelectedNetwork */, carrierConfig, false /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchUnselectedWifi() {
+ verifyMatchWifi(
+ false /* isSelectedNetwork */, null /* carrierConfig */, true /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchUnselectedWifiBelowRssiThreshold() {
+ final PersistableBundle carrierConfig = new PersistableBundle();
+ carrierConfig.putInt(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH);
+
+ verifyMatchWifi(false /* isSelectedNetwork */, carrierConfig, false /* expectMatch */);
+ }
+
+ private void verifyMatchWifiWithSsid(boolean useMatchedSsid, boolean expectMatch) {
+ final String nwPrioritySsid = useMatchedSsid ? SSID : SSID_OTHER;
+ final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority =
+ new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setSsid(nwPrioritySsid)
+ .build();
+
+ assertEquals(
+ expectMatch,
+ checkMatchesWifiPriorityRule(
+ wifiNetworkPriority,
+ mWifiNetworkRecord,
+ null /* currentlySelecetd */,
+ null /* carrierConfig */));
+ }
+
+ @Test
+ public void testMatchWifiWithSsid() {
+ verifyMatchWifiWithSsid(true /* useMatchedSsid */, true /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchWifiFailWithWrongSsid() {
+ verifyMatchWifiWithSsid(false /* useMatchedSsid */, false /* expectMatch */);
+ }
+
+ private static VcnCellUnderlyingNetworkPriority.Builder getCellNetworkPriorityBuilder() {
+ return new VcnCellUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setAllowRoaming(true /* allowRoaming */);
+ }
+
+ @Test
+ public void testMatchMacroCell() {
+ assertTrue(
+ checkMatchesCellPriorityRule(
+ mVcnContext,
+ getCellNetworkPriorityBuilder().build(),
+ mCellNetworkRecord,
+ SUB_GROUP,
+ mSubscriptionSnapshot));
+ }
+
+ @Test
+ public void testMatchOpportunisticCell() {
+ final VcnCellUnderlyingNetworkPriority opportunisticCellNetworkPriority =
+ getCellNetworkPriorityBuilder()
+ .setRequireOpportunistic(true /* requireOpportunistic */)
+ .build();
+
+ when(mSubscriptionSnapshot.isOpportunistic(SUB_ID)).thenReturn(true);
+ when(mSubscriptionSnapshot.getAllSubIdsInGroup(SUB_GROUP)).thenReturn(new ArraySet<>());
+
+ assertTrue(
+ checkMatchesCellPriorityRule(
+ mVcnContext,
+ opportunisticCellNetworkPriority,
+ mCellNetworkRecord,
+ SUB_GROUP,
+ mSubscriptionSnapshot));
+ }
+
+ private void verifyMatchMacroCellWithAllowedPlmnIds(
+ boolean useMatchedPlmnId, boolean expectMatch) {
+ final String networkPriorityPlmnId = useMatchedPlmnId ? PLMN_ID : PLMN_ID_OTHER;
+ final VcnCellUnderlyingNetworkPriority networkPriority =
+ getCellNetworkPriorityBuilder()
+ .setAllowedOperatorPlmnIds(Set.of(networkPriorityPlmnId))
+ .build();
+
+ assertEquals(
+ expectMatch,
+ checkMatchesCellPriorityRule(
+ mVcnContext,
+ networkPriority,
+ mCellNetworkRecord,
+ SUB_GROUP,
+ mSubscriptionSnapshot));
+ }
+
+ @Test
+ public void testMatchMacroCellWithAllowedPlmnIds() {
+ verifyMatchMacroCellWithAllowedPlmnIds(true /* useMatchedPlmnId */, true /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchMacroCellFailWithDisallowedPlmnIds() {
+ verifyMatchMacroCellWithAllowedPlmnIds(
+ false /* useMatchedPlmnId */, false /* expectMatch */);
+ }
+
+ private void verifyMatchMacroCellWithAllowedSpecificCarrierIds(
+ boolean useMatchedCarrierId, boolean expectMatch) {
+ final int networkPriorityCarrierId = useMatchedCarrierId ? CARRIER_ID : CARRIER_ID_OTHER;
+ final VcnCellUnderlyingNetworkPriority networkPriority =
+ getCellNetworkPriorityBuilder()
+ .setAllowedSpecificCarrierIds(Set.of(networkPriorityCarrierId))
+ .build();
+
+ assertEquals(
+ expectMatch,
+ checkMatchesCellPriorityRule(
+ mVcnContext,
+ networkPriority,
+ mCellNetworkRecord,
+ SUB_GROUP,
+ mSubscriptionSnapshot));
+ }
+
+ @Test
+ public void testMatchMacroCellWithAllowedSpecificCarrierIds() {
+ verifyMatchMacroCellWithAllowedSpecificCarrierIds(
+ true /* useMatchedCarrierId */, true /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchMacroCellFailWithDisallowedSpecificCarrierIds() {
+ verifyMatchMacroCellWithAllowedSpecificCarrierIds(
+ false /* useMatchedCarrierId */, false /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchWifiFailWithoutNotRoamingBit() {
+ final VcnCellUnderlyingNetworkPriority networkPriority =
+ getCellNetworkPriorityBuilder().setAllowRoaming(false /* allowRoaming */).build();
+
+ assertFalse(
+ checkMatchesCellPriorityRule(
+ mVcnContext,
+ networkPriority,
+ mCellNetworkRecord,
+ SUB_GROUP,
+ mSubscriptionSnapshot));
+ }
+
+ private void verifyCalculatePriorityClass(
+ UnderlyingNetworkRecord networkRecord, int expectedIndex) {
+ final int priorityIndex =
+ calculatePriorityClass(
+ mVcnContext,
+ networkRecord,
+ VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_PRIORITIES,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ null /* currentlySelected */,
+ null /* carrierConfig */);
+
+ assertEquals(expectedIndex, priorityIndex);
+ }
+
+ @Test
+ public void testCalculatePriorityClass() throws Exception {
+ verifyCalculatePriorityClass(mCellNetworkRecord, 2);
+ }
+
+ @Test
+ public void testCalculatePriorityClassFailToMatchAny() throws Exception {
+ final NetworkCapabilities nc =
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setSignalStrength(WIFI_RSSI_LOW)
+ .setSsid(SSID)
+ .build();
+ final UnderlyingNetworkRecord wifiNetworkRecord =
+ new UnderlyingNetworkRecord(mNetwork, nc, LINK_PROPERTIES, false /* isBlocked */);
+
+ verifyCalculatePriorityClass(wifiNetworkRecord, PRIORITY_ANY);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
similarity index 77%
rename from tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
rename to tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
index 5af69b5..fad9669 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-package com.android.server.vcn;
+package com.android.server.vcn.routeselection;
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -40,6 +42,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.os.ParcelUuid;
import android.os.test.TestLooper;
import android.telephony.CarrierConfigManager;
@@ -48,10 +51,11 @@
import android.util.ArraySet;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
-import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkListener;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
+import com.android.server.vcn.VcnContext;
+import com.android.server.vcn.VcnNetworkProvider;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController.NetworkBringupCallback;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener;
import org.junit.Before;
import org.junit.Test;
@@ -64,7 +68,7 @@
import java.util.Set;
import java.util.UUID;
-public class UnderlyingNetworkTrackerTest {
+public class UnderlyingNetworkControllerTest {
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
private static final int INITIAL_SUB_ID_1 = 1;
private static final int INITIAL_SUB_ID_2 = 2;
@@ -102,14 +106,14 @@
@Mock private TelephonyManager mTelephonyManager;
@Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
- @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
+ @Mock private UnderlyingNetworkControllerCallback mNetworkControllerCb;
@Mock private Network mNetwork;
@Captor private ArgumentCaptor<UnderlyingNetworkListener> mUnderlyingNetworkListenerCaptor;
private TestLooper mTestLooper;
private VcnContext mVcnContext;
- private UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+ private UnderlyingNetworkController mUnderlyingNetworkController;
@Before
public void setUp() {
@@ -140,12 +144,13 @@
when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS);
- mUnderlyingNetworkTracker =
- new UnderlyingNetworkTracker(
+ mUnderlyingNetworkController =
+ new UnderlyingNetworkController(
mVcnContext,
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
SUB_GROUP,
mSubscriptionSnapshot,
- mNetworkTrackerCb);
+ mNetworkControllerCb);
}
private void resetVcnContext() {
@@ -153,7 +158,8 @@
doNothing().when(mVcnContext).ensureRunningOnLooperThread();
}
- private static LinkProperties getLinkPropertiesWithName(String iface) {
+ // Package private for use in NetworkPriorityClassifierTest
+ static LinkProperties getLinkPropertiesWithName(String iface) {
LinkProperties linkProperties = new LinkProperties();
linkProperties.setInterfaceName(iface);
return linkProperties;
@@ -181,11 +187,12 @@
mVcnNetworkProvider,
true /* isInTestMode */);
- new UnderlyingNetworkTracker(
+ new UnderlyingNetworkController(
vcnContext,
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
SUB_GROUP,
mSubscriptionSnapshot,
- mNetworkTrackerCb);
+ mNetworkControllerCb);
verify(cm)
.registerNetworkCallback(
@@ -233,7 +240,7 @@
mock(TelephonySubscriptionSnapshot.class);
when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS);
- mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate);
+ mUnderlyingNetworkController.updateSubscriptionSnapshot(subscriptionUpdate);
// verify that initially-filed bringup requests are unregistered (cell + wifi)
verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 3))
@@ -255,7 +262,7 @@
return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setSubscriptionIds(netCapsSubIds)
- .setSignalStrength(UnderlyingNetworkTracker.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT)
+ .setSignalStrength(WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT)
.build();
}
@@ -264,7 +271,7 @@
return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setSubscriptionIds(netCapsSubIds)
- .setSignalStrength(UnderlyingNetworkTracker.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT)
+ .setSignalStrength(WIFI_EXIT_RSSI_THRESHOLD_DEFAULT)
.build();
}
@@ -304,7 +311,7 @@
@Test
public void testTeardown() {
- mUnderlyingNetworkTracker.teardown();
+ mUnderlyingNetworkController.teardown();
// Expect 5 NetworkBringupCallbacks to be unregistered: 1 for WiFi, 2 for Cellular (1x for
// each subId), and 1 for each of the Wifi signal strength thresholds
@@ -348,6 +355,17 @@
return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES);
}
+ private static NetworkCapabilities buildResponseNwCaps(
+ NetworkCapabilities requestNetworkCaps, Set<Integer> netCapsSubIds) {
+ final TelephonyNetworkSpecifier telephonyNetworkSpecifier =
+ new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(netCapsSubIds.iterator().next())
+ .build();
+ return new NetworkCapabilities.Builder(requestNetworkCaps)
+ .setNetworkSpecifier(telephonyNetworkSpecifier)
+ .build();
+ }
+
private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback(
NetworkCapabilities networkCapabilities) {
verify(mConnectivityManager)
@@ -358,17 +376,20 @@
UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue();
cb.onAvailable(mNetwork);
- cb.onCapabilitiesChanged(mNetwork, networkCapabilities);
+
+ final NetworkCapabilities responseNetworkCaps =
+ buildResponseNwCaps(networkCapabilities, INITIAL_SUB_IDS);
+ cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES);
cb.onBlockedStatusChanged(mNetwork, false /* isFalse */);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
mNetwork,
- networkCapabilities,
+ responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
return cb;
}
@@ -376,15 +397,17 @@
public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() {
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
- cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
+ final NetworkCapabilities responseNetworkCaps =
+ buildResponseNwCaps(UPDATED_NETWORK_CAPABILITIES, UPDATED_SUB_IDS);
+ cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
mNetwork,
- UPDATED_NETWORK_CAPABILITIES,
+ responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -396,29 +419,33 @@
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
mNetwork,
- INITIAL_NETWORK_CAPABILITIES,
+ buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
UPDATED_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
- cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
+ final NetworkCapabilities responseNetworkCaps =
+ buildResponseNwCaps(SUSPENDED_NETWORK_CAPABILITIES, UPDATED_SUB_IDS);
+ cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
mNetwork,
- SUSPENDED_NETWORK_CAPABILITIES,
+ responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb, times(1))
+ .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
// change.
- cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
+ verify(mNetworkControllerCb, times(1))
+ .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -426,19 +453,23 @@
UnderlyingNetworkListener cb =
verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
- cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+ final NetworkCapabilities responseNetworkCaps =
+ buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS);
+ cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
mNetwork,
- INITIAL_NETWORK_CAPABILITIES,
+ responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb, times(1))
+ .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
// change.
- cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
+ verify(mNetworkControllerCb, times(1))
+ .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -450,10 +481,10 @@
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
mNetwork,
- INITIAL_NETWORK_CAPABILITIES,
+ buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
INITIAL_LINK_PROPERTIES,
true /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -462,29 +493,31 @@
cb.onLost(mNetwork);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(null);
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null);
}
@Test
public void testRecordTrackerCallbackIgnoresDuplicateRecord() {
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
- cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+ cb.onCapabilitiesChanged(
+ mNetwork, buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS));
- // Verify no more calls to the UnderlyingNetworkTrackerCallback when the
+ // Verify no more calls to the UnderlyingNetworkControllerCallback when the
// UnderlyingNetworkRecord does not actually change
- verifyNoMoreInteractions(mNetworkTrackerCb);
+ verifyNoMoreInteractions(mNetworkControllerCb);
}
@Test
public void testRecordTrackerCallbackNotifiedAfterTeardown() {
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
- mUnderlyingNetworkTracker.teardown();
+ mUnderlyingNetworkController.teardown();
- cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
+ cb.onCapabilitiesChanged(
+ mNetwork, buildResponseNwCaps(UPDATED_NETWORK_CAPABILITIES, INITIAL_SUB_IDS));
// Verify that the only call was during onAvailable()
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
+ verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
}
// TODO (b/187991063): Add tests for network prioritization