Merge "Import TLS handshake atom for Conscrypt"
diff --git a/Android.bp b/Android.bp
index 35879df..9c33106 100644
--- a/Android.bp
+++ b/Android.bp
@@ -554,6 +554,7 @@
"framework-platform-compat-config",
// TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
"gps_debug.conf",
+ "icu4j-platform-compat-config",
"libcore-platform-compat-config",
"protolog.conf.json.gz",
"services-platform-compat-config",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 9047df5..cff96b7 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -312,14 +312,7 @@
}
java_library_static {
- name: "android_monolith_stubs_current",
- srcs: [ ":api-stubs-docs" ],
- static_libs: [ "private-stub-annotations-jar" ],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
- name: "android_merged_stubs_current",
+ name: "android_stubs_current",
srcs: [ ":api-stubs-docs-non-updatable" ],
static_libs: [
"conscrypt.module.public.api.stubs",
@@ -332,19 +325,6 @@
"framework-wifi.stubs",
"private-stub-annotations-jar",
],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
- name: "android_stubs_current",
- static_libs: ["android_merged_stubs_current"],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
- name: "android_system_monolith_stubs_current",
- srcs: [ ":system-api-stubs-docs" ],
- static_libs: [ "private-stub-annotations-jar" ],
defaults: [
"android_defaults_stubs_current",
"android_stubs_dists_default",
@@ -363,7 +343,7 @@
}
java_library_static {
- name: "android_system_merged_stubs_current",
+ name: "android_system_stubs_current",
srcs: [ ":system-api-stubs-docs-non-updatable" ],
static_libs: [
"conscrypt.module.public.api.stubs",
@@ -380,12 +360,6 @@
}
java_library_static {
- name: "android_system_stubs_current",
- static_libs: ["android_system_merged_stubs_current"],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
name: "android_test_stubs_current",
srcs: [ ":test-api-stubs-docs" ],
static_libs: [
diff --git a/apex/Android.bp b/apex/Android.bp
index c5b4901..0a535a8 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -112,6 +112,8 @@
],
stubs_source_visibility: ["//visibility:private"],
+ defaults_visibility: ["//visibility:private"],
+
// Collates API usages from each module for further analysis.
plugins: ["java_api_finder"],
diff --git a/api/current.txt b/api/current.txt
index c2e75cd..ee3f81e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38641,6 +38641,9 @@
ctor public CallLog.Calls();
method public static String getLastOutgoingCall(android.content.Context);
field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
+ field public static final long AUTO_MISSED_EMERGENCY_CALL = 1L; // 0x1L
+ field public static final long AUTO_MISSED_MAXIMUM_DIALING = 4L; // 0x4L
+ field public static final long AUTO_MISSED_MAXIMUM_RINGING = 2L; // 0x2L
field public static final int BLOCKED_TYPE = 6; // 0x6
field public static final String BLOCK_REASON = "block_reason";
field public static final int BLOCK_REASON_BLOCKED_NUMBER = 3; // 0x3
@@ -38686,6 +38689,8 @@
field public static final String IS_READ = "is_read";
field public static final String LAST_MODIFIED = "last_modified";
field public static final String LIMIT_PARAM_KEY = "limit";
+ field public static final String MISSED_REASON = "missed_reason";
+ field public static final long MISSED_REASON_NOT_MISSED = 0L; // 0x0L
field public static final int MISSED_TYPE = 3; // 0x3
field public static final String NEW = "new";
field public static final String NUMBER = "number";
@@ -38702,6 +38707,13 @@
field public static final int REJECTED_TYPE = 5; // 0x5
field public static final String TRANSCRIPTION = "transcription";
field public static final String TYPE = "type";
+ field public static final long USER_MISSED_CALL_FILTERS_TIMEOUT = 4194304L; // 0x400000L
+ field public static final long USER_MISSED_CALL_SCREENING_SERVICE_SILENCED = 2097152L; // 0x200000L
+ field public static final long USER_MISSED_DND_MODE = 262144L; // 0x40000L
+ field public static final long USER_MISSED_LOW_RING_VOLUME = 524288L; // 0x80000L
+ field public static final long USER_MISSED_NO_ANSWER = 65536L; // 0x10000L
+ field public static final long USER_MISSED_NO_VIBRATE = 1048576L; // 0x100000L
+ field public static final long USER_MISSED_SHORT_RING = 131072L; // 0x20000L
field public static final String VIA_NUMBER = "via_number";
field public static final int VOICEMAIL_TYPE = 4; // 0x4
field public static final String VOICEMAIL_URI = "voicemail_uri";
diff --git a/api/system-current.txt b/api/system-current.txt
index 5ea8e43..9a27584 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -369,6 +369,7 @@
field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
+ field public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn";
field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
field public static final String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
@@ -11735,6 +11736,17 @@
package android.telephony.ims {
+ public final class AudioCodecAttributes implements android.os.Parcelable {
+ ctor public AudioCodecAttributes(float, @NonNull android.util.Range<java.lang.Float>, float, @NonNull android.util.Range<java.lang.Float>);
+ method public int describeContents();
+ method public float getBandwidthKhz();
+ method @NonNull public android.util.Range<java.lang.Float> getBandwidthRangeKhz();
+ method public float getBitrateKbps();
+ method @NonNull public android.util.Range<java.lang.Float> getBitrateRangeKbps();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.AudioCodecAttributes> CREATOR;
+ }
+
public final class ImsCallForwardInfo implements android.os.Parcelable {
ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
method public int describeContents();
@@ -12103,6 +12115,7 @@
ctor public ImsStreamMediaProfile(int, int, int, int, int);
method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
+ method @Nullable public android.telephony.ims.AudioCodecAttributes getAudioCodecAttributes();
method public int getAudioDirection();
method public int getAudioQuality();
method public int getRttMode();
@@ -12110,6 +12123,7 @@
method public int getVideoQuality();
method public boolean isReceivingRttAudio();
method public boolean isRttCall();
+ method public void setAudioCodecAttributes(@NonNull android.telephony.ims.AudioCodecAttributes);
method public void setReceivingRttAudio(boolean);
method public void setRttMode(int);
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/api/current.txt b/core/api/current.txt
index ab0aec7..23ddda6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -37208,6 +37208,9 @@
ctor public CallLog.Calls();
method public static String getLastOutgoingCall(android.content.Context);
field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
+ field public static final long AUTO_MISSED_EMERGENCY_CALL = 1L; // 0x1L
+ field public static final long AUTO_MISSED_MAXIMUM_DIALING = 4L; // 0x4L
+ field public static final long AUTO_MISSED_MAXIMUM_RINGING = 2L; // 0x2L
field public static final int BLOCKED_TYPE = 6; // 0x6
field public static final String BLOCK_REASON = "block_reason";
field public static final int BLOCK_REASON_BLOCKED_NUMBER = 3; // 0x3
@@ -37253,6 +37256,8 @@
field public static final String IS_READ = "is_read";
field public static final String LAST_MODIFIED = "last_modified";
field public static final String LIMIT_PARAM_KEY = "limit";
+ field public static final String MISSED_REASON = "missed_reason";
+ field public static final long MISSED_REASON_NOT_MISSED = 0L; // 0x0L
field public static final int MISSED_TYPE = 3; // 0x3
field public static final String NEW = "new";
field public static final String NUMBER = "number";
@@ -37269,6 +37274,13 @@
field public static final int REJECTED_TYPE = 5; // 0x5
field public static final String TRANSCRIPTION = "transcription";
field public static final String TYPE = "type";
+ field public static final long USER_MISSED_CALL_FILTERS_TIMEOUT = 4194304L; // 0x400000L
+ field public static final long USER_MISSED_CALL_SCREENING_SERVICE_SILENCED = 2097152L; // 0x200000L
+ field public static final long USER_MISSED_DND_MODE = 262144L; // 0x40000L
+ field public static final long USER_MISSED_LOW_RING_VOLUME = 524288L; // 0x80000L
+ field public static final long USER_MISSED_NO_ANSWER = 65536L; // 0x10000L
+ field public static final long USER_MISSED_NO_VIBRATE = 1048576L; // 0x100000L
+ field public static final long USER_MISSED_SHORT_RING = 131072L; // 0x20000L
field public static final String VIA_NUMBER = "via_number";
field public static final int VOICEMAIL_TYPE = 4; // 0x4
field public static final String VOICEMAIL_URI = "voicemail_uri";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 7db113d..28e5804 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -369,6 +369,7 @@
field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
+ field public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn";
field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
field public static final String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
@@ -10617,6 +10618,17 @@
package android.telephony.ims {
+ public final class AudioCodecAttributes implements android.os.Parcelable {
+ ctor public AudioCodecAttributes(float, @NonNull android.util.Range<java.lang.Float>, float, @NonNull android.util.Range<java.lang.Float>);
+ method public int describeContents();
+ method public float getBandwidthKhz();
+ method @NonNull public android.util.Range<java.lang.Float> getBandwidthRangeKhz();
+ method public float getBitrateKbps();
+ method @NonNull public android.util.Range<java.lang.Float> getBitrateRangeKbps();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.AudioCodecAttributes> CREATOR;
+ }
+
public final class ImsCallForwardInfo implements android.os.Parcelable {
ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
method public int describeContents();
@@ -10985,6 +10997,7 @@
ctor public ImsStreamMediaProfile(int, int, int, int, int);
method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
+ method @Nullable public android.telephony.ims.AudioCodecAttributes getAudioCodecAttributes();
method public int getAudioDirection();
method public int getAudioQuality();
method public int getRttMode();
@@ -10992,6 +11005,7 @@
method public int getVideoQuality();
method public boolean isReceivingRttAudio();
method public boolean isRttCall();
+ method public void setAudioCodecAttributes(@NonNull android.telephony.ims.AudioCodecAttributes);
method public void setReceivingRttAudio(boolean);
method public void setRttMode(int);
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 0d5bb11..1c8c6c1 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1439,6 +1439,7 @@
@SystemApi
public static final String OPSTR_INTERACT_ACROSS_PROFILES = "android:interact_across_profiles";
/** @hide Start Platform VPN without user intervention */
+ @SystemApi
public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn";
/** @hide */
@SystemApi
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 93bff3c..7391b0c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -207,7 +207,7 @@
* <p>
* Avoids spamming the system with overly large strings such as full e-mails.
*/
- private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
+ private static final int MAX_CHARSEQUENCE_LENGTH = 1024;
/**
* Maximum entries of reply text that are accepted by Builder and friends.
@@ -7830,7 +7830,7 @@
*/
public Message(@NonNull CharSequence text, long timestamp, @Nullable Person sender,
boolean remoteInputHistory) {
- mText = text;
+ mText = safeCharSequence(text);
mTimestamp = timestamp;
mSender = sender;
mRemoteInputHistory = remoteInputHistory;
@@ -7944,7 +7944,7 @@
bundle.putLong(KEY_TIMESTAMP, mTimestamp);
if (mSender != null) {
// Legacy listeners need this
- bundle.putCharSequence(KEY_SENDER, mSender.getName());
+ bundle.putCharSequence(KEY_SENDER, safeCharSequence(mSender.getName()));
bundle.putParcelable(KEY_SENDER_PERSON, mSender);
}
if (mDataMimeType != null) {
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 19242ba..ffa537e 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -88,6 +88,26 @@
public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
/**
+ * Checks if an app with given uid is an active device owner of its user.
+ *
+ * <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held.
+ *
+ * @param uid App uid.
+ * @return true if the uid is an active device owner.
+ */
+ public abstract boolean isActiveDeviceOwner(int uid);
+
+ /**
+ * Checks if an app with given uid is an active profile owner of its user.
+ *
+ * <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held.
+ *
+ * @param uid App uid.
+ * @return true if the uid is an active profile owner.
+ */
+ public abstract boolean isActiveProfileOwner(int uid);
+
+ /**
* Checks if an app with given uid is the active supervision admin.
*
* <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held.
diff --git a/core/java/android/os/LocaleList.java b/core/java/android/os/LocaleList.java
index ab4bb0b..9c0bc45 100644
--- a/core/java/android/os/LocaleList.java
+++ b/core/java/android/os/LocaleList.java
@@ -25,6 +25,7 @@
import com.android.internal.annotations.GuardedBy;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@@ -151,18 +152,18 @@
/**
* Creates a new {@link LocaleList}.
*
+ * If two or more same locales are passed, the repeated locales will be dropped.
* <p>For empty lists of {@link Locale} items it is better to use {@link #getEmptyLocaleList()},
* which returns a pre-constructed empty list.</p>
*
* @throws NullPointerException if any of the input locales is <code>null</code>.
- * @throws IllegalArgumentException if any of the input locales repeat.
*/
public LocaleList(@NonNull Locale... list) {
if (list.length == 0) {
mList = sEmptyList;
mStringRepresentation = "";
} else {
- final Locale[] localeList = new Locale[list.length];
+ final ArrayList<Locale> localeList = new ArrayList<>();
final HashSet<Locale> seenLocales = new HashSet<Locale>();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.length; i++) {
@@ -170,10 +171,10 @@
if (l == null) {
throw new NullPointerException("list[" + i + "] is null");
} else if (seenLocales.contains(l)) {
- throw new IllegalArgumentException("list[" + i + "] is a repetition");
+ // Dropping duplicated locale entries.
} else {
final Locale localeClone = (Locale) l.clone();
- localeList[i] = localeClone;
+ localeList.add(localeClone);
sb.append(localeClone.toLanguageTag());
if (i < list.length - 1) {
sb.append(',');
@@ -181,7 +182,7 @@
seenLocales.add(localeClone);
}
}
- mList = localeList;
+ mList = localeList.toArray(new Locale[localeList.size()]);
mStringRepresentation = sb.toString();
}
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 276f162..65132f0 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -17,6 +17,7 @@
package android.provider;
+import android.annotation.LongDef;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -43,6 +44,8 @@
import android.text.TextUtils;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -611,6 +614,144 @@
*/
public static final String BLOCK_REASON = "block_reason";
+ /** @hide */
+ @LongDef(flag = true, value = {
+ MISSED_REASON_NOT_MISSED,
+ AUTO_MISSED_EMERGENCY_CALL,
+ AUTO_MISSED_MAXIMUM_RINGING,
+ AUTO_MISSED_MAXIMUM_DIALING,
+ USER_MISSED_NO_ANSWER,
+ USER_MISSED_SHORT_RING,
+ USER_MISSED_DND_MODE,
+ USER_MISSED_LOW_RING_VOLUME,
+ USER_MISSED_NO_VIBRATE,
+ USER_MISSED_CALL_SCREENING_SERVICE_SILENCED,
+ USER_MISSED_CALL_FILTERS_TIMEOUT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MissedReason {}
+
+ /**
+ * Value for {@link CallLog.Calls#MISSED_REASON}, set as the default value when a call was
+ * not missed.
+ */
+ public static final long MISSED_REASON_NOT_MISSED = 0;
+
+ /**
+ * Value for {@link CallLog.Calls#MISSED_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#MISSED_TYPE} to indicate that a call was automatically rejected by
+ * system because an ongoing emergency call.
+ */
+ public static final long AUTO_MISSED_EMERGENCY_CALL = 1 << 0;
+
+ /**
+ * Value for {@link CallLog.Calls#MISSED_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#MISSED_TYPE} to indicate that a call was automatically rejected by
+ * system because the system cannot support any more ringing calls.
+ */
+ public static final long AUTO_MISSED_MAXIMUM_RINGING = 1 << 1;
+
+ /**
+ * Value for {@link CallLog.Calls#MISSED_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#MISSED_TYPE} to indicate that a call was automatically rejected by
+ * system because the system cannot support any more dialing calls.
+ */
+ public static final long AUTO_MISSED_MAXIMUM_DIALING = 1 << 2;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, set this bit when
+ * the call was missed just because user didn't answer it.
+ */
+ public static final long USER_MISSED_NO_ANSWER = 1 << 16;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, set this bit when
+ * this call rang for a short period of time.
+ */
+ public static final long USER_MISSED_SHORT_RING = 1 << 17;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, when this call
+ * rings less than this defined time in millisecond, set
+ * {@link CallLog.Calls#USER_MISSED_SHORT_RING} bit.
+ * @hide
+ */
+ public static final long SHORT_RING_THRESHOLD = 5000L;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, set this bit when
+ * this call is silenced because the phone is in 'do not disturb mode'.
+ */
+ public static final long USER_MISSED_DND_MODE = 1 << 18;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, set this bit when
+ * this call rings with a low ring volume.
+ */
+ public static final long USER_MISSED_LOW_RING_VOLUME = 1 << 19;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, when this call
+ * rings in volume less than this defined volume threshold, set
+ * {@link CallLog.Calls#USER_MISSED_LOW_RING_VOLUME} bit.
+ * @hide
+ */
+ public static final int LOW_RING_VOLUME = 0;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE} set this bit when
+ * this call rings without vibration.
+ */
+ public static final long USER_MISSED_NO_VIBRATE = 1 << 20;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, set this bit when
+ * this call is silenced by the call screening service.
+ */
+ public static final long USER_MISSED_CALL_SCREENING_SERVICE_SILENCED = 1 << 21;
+
+ /**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, set this bit when
+ * the call filters timed out.
+ */
+ public static final long USER_MISSED_CALL_FILTERS_TIMEOUT = 1 << 22;
+
+ /**
+ * Where the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE},
+ * indicates factors which may have lead the user to miss the call.
+ * <P>Type: INTEGER</P>
+ *
+ * <p>
+ * There are two main cases. Auto missed cases and user missed cases. Default value is:
+ * <ul>
+ * <li>{@link CallLog.Calls#MISSED_REASON_NOT_MISSED}</li>
+ * </ul>
+ * </p>
+ * <P>
+ * Auto missed cases are those where a call was missed because it was not possible for the
+ * incoming call to be presented to the user at all. Possible values are:
+ * <ul>
+ * <li>{@link CallLog.Calls#AUTO_MISSED_EMERGENCY_CALL}</li>
+ * <li>{@link CallLog.Calls#AUTO_MISSED_MAXIMUM_RINGING}</li>
+ * <li>{@link CallLog.Calls#AUTO_MISSED_MAXIMUM_DIALING}</li>
+ * </ul>
+ * </P>
+ * <P>
+ * User missed cases are those where the incoming call was presented to the user, but
+ * factors such as a low ringing volume may have contributed to the call being missed.
+ * Following bits can be set to indicate possible reasons for this:
+ * <ul>
+ * <li>{@link CallLog.Calls#USER_MISSED_SHORT_RING}</li>
+ * <li>{@link CallLog.Calls#USER_MISSED_DND_MODE}</li>
+ * <li>{@link CallLog.Calls#USER_MISSED_LOW_RING_VOLUME}</li>
+ * <li>{@link CallLog.Calls#USER_MISSED_NO_VIBRATE}</li>
+ * <li>{@link CallLog.Calls#USER_MISSED_CALL_SCREENING_SERVICE_SILENCED}</li>
+ * <li>{@link CallLog.Calls#USER_MISSED_CALL_FILTERS_TIMEOUT}</li>
+ * </ul>
+ * </P>
+ */
+ public static final String MISSED_REASON = "missed_reason";
+
/**
* Adds a call to the call log.
*
@@ -635,12 +776,13 @@
public static Uri addCall(CallerInfo ci, Context context, String number,
int presentation, int callType, int features,
PhoneAccountHandle accountHandle,
- long start, int duration, Long dataUsage) {
+ long start, int duration, Long dataUsage, long missedReason) {
return addCall(ci, context, number, "" /* postDialDigits */, "" /* viaNumber */,
presentation, callType, features, accountHandle, start, duration,
dataUsage, false /* addForAllUsers */, null /* userToBeInsertedTo */,
false /* isRead */, Calls.BLOCK_REASON_NOT_BLOCKED /* callBlockReason */,
- null /* callScreeningAppName */, null /* callScreeningComponentName */);
+ null /* callScreeningAppName */, null /* callScreeningComponentName */,
+ missedReason);
}
@@ -675,12 +817,13 @@
public static Uri addCall(CallerInfo ci, Context context, String number,
String postDialDigits, String viaNumber, int presentation, int callType,
int features, PhoneAccountHandle accountHandle, long start, int duration,
- Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) {
+ Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
+ long missedReason) {
return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType,
features, accountHandle, start, duration, dataUsage, addForAllUsers,
userToBeInsertedTo, false /* isRead */ , Calls.BLOCK_REASON_NOT_BLOCKED
/* callBlockReason */, null /* callScreeningAppName */,
- null /* callScreeningComponentName */);
+ null /* callScreeningComponentName */, missedReason);
}
/**
@@ -714,6 +857,7 @@
* @param callBlockReason The reason why the call is blocked.
* @param callScreeningAppName The call screening application name which block the call.
* @param callScreeningComponentName The call screening component name which block the call.
+ * @param missedReason The encoded missed information of the call.
*
* @result The URI of the call log entry belonging to the user that made or received this
* call. This could be of the shadow provider. Do not return it to non-system apps,
@@ -726,7 +870,7 @@
int features, PhoneAccountHandle accountHandle, long start, int duration,
Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
boolean isRead, int callBlockReason, CharSequence callScreeningAppName,
- String callScreeningComponentName) {
+ String callScreeningComponentName, long missedReason) {
if (VERBOSE_LOG) {
Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
number, userToBeInsertedTo, addForAllUsers));
@@ -779,6 +923,7 @@
values.put(BLOCK_REASON, callBlockReason);
values.put(CALL_SCREENING_APP_NAME, charSequenceToString(callScreeningAppName));
values.put(CALL_SCREENING_COMPONENT_NAME, callScreeningComponentName);
+ values.put(MISSED_REASON, Long.valueOf(missedReason));
if ((ci != null) && (ci.getContactId() > 0)) {
// Update usage information for the number associated with the contact ID.
@@ -1114,5 +1259,19 @@
}
return countryIso;
}
+
+ /**
+ * Check if the missedReason code indicate that the call was user missed or automatically
+ * rejected by system.
+ *
+ * @param missedReason
+ * The result is true if the call was user missed, false if the call was automatically
+ * rejected by system.
+ *
+ * @hide
+ */
+ public static boolean isUserMissed(long missedReason) {
+ return missedReason >= (USER_MISSED_NO_ANSWER);
+ }
}
}
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
index e1fb932..52e1e58 100644
--- a/core/java/android/timezone/TzDataSetVersion.java
+++ b/core/java/android/timezone/TzDataSetVersion.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
+import com.android.i18n.timezone.TimeZoneDataFiles;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
@@ -75,8 +76,7 @@
@NonNull
public static TzDataSetVersion read() throws IOException, TzDataSetException {
try {
- return new TzDataSetVersion(
- com.android.i18n.timezone.TzDataSetVersion.readTimeZoneModuleVersion());
+ return new TzDataSetVersion(TimeZoneDataFiles.readTimeZoneModuleVersion());
} catch (com.android.i18n.timezone.TzDataSetVersion.TzDataSetException e) {
throw new TzDataSetException(e.getMessage(), e);
}
diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index c3e2ecc..33bc121 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -17,6 +17,10 @@
package android.uwb;
import android.annotation.FloatRange;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* Angle measurement
@@ -26,7 +30,7 @@
*
* @hide
*/
-public final class AngleMeasurement {
+public final class AngleMeasurement implements Parcelable {
private final double mRadians;
private final double mErrorRadians;
private final double mConfidenceLevel;
@@ -39,7 +43,7 @@
/**
* Angle measurement in radians
- *
+ *
* @return angle in radians
*/
@FloatRange(from = -Math.PI, to = +Math.PI)
@@ -74,6 +78,61 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof AngleMeasurement) {
+ AngleMeasurement other = (AngleMeasurement) obj;
+ return mRadians == other.getRadians()
+ && mErrorRadians == other.getErrorRadians()
+ && mConfidenceLevel == other.getConfidenceLevel();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRadians, mErrorRadians, mConfidenceLevel);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeDouble(mRadians);
+ dest.writeDouble(mErrorRadians);
+ dest.writeDouble(mConfidenceLevel);
+ }
+
+ public static final @android.annotation.NonNull Creator<AngleMeasurement> CREATOR =
+ new Creator<AngleMeasurement>() {
+ @Override
+ public AngleMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setRadians(in.readDouble());
+ builder.setErrorRadians(in.readDouble());
+ builder.setConfidenceLevel(in.readDouble());
+ return builder.build();
+ }
+
+ @Override
+ public AngleMeasurement[] newArray(int size) {
+ return new AngleMeasurement[size];
+ }
+ };
+
+ /**
* Builder class for {@link AngleMeasurement}.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
index a7b5eae..cd5af69 100644
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java
@@ -18,13 +18,17 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* Represents an angle of arrival measurement between two devices using Ultra Wideband
*
* @hide
*/
-public final class AngleOfArrivalMeasurement {
+public final class AngleOfArrivalMeasurement implements Parcelable {
private final AngleMeasurement mAzimuthAngleMeasurement;
private final AngleMeasurement mAltitudeAngleMeasurement;
@@ -71,6 +75,63 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof AngleOfArrivalMeasurement) {
+ AngleOfArrivalMeasurement other = (AngleOfArrivalMeasurement) obj;
+ return mAzimuthAngleMeasurement.equals(other.getAzimuth())
+ && mAltitudeAngleMeasurement.equals(other.getAltitude());
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAzimuthAngleMeasurement, mAltitudeAngleMeasurement);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mAzimuthAngleMeasurement, flags);
+ dest.writeParcelable(mAltitudeAngleMeasurement, flags);
+ }
+
+ public static final @android.annotation.NonNull Creator<AngleOfArrivalMeasurement> CREATOR =
+ new Creator<AngleOfArrivalMeasurement>() {
+ @Override
+ public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+
+ builder.setAzimuthAngleMeasurement(
+ in.readParcelable(AngleMeasurement.class.getClassLoader()));
+
+ builder.setAltitudeAngleMeasurement(
+ in.readParcelable(AngleMeasurement.class.getClassLoader()));
+
+ return builder.build();
+ }
+
+ @Override
+ public AngleOfArrivalMeasurement[] newArray(int size) {
+ return new AngleOfArrivalMeasurement[size];
+ }
+ };
+
+ /**
* Builder class for {@link AngleOfArrivalMeasurement}.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 4cd5d83..c959840 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -17,6 +17,11 @@
package android.uwb;
import android.annotation.FloatRange;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* A data point for the distance measurement
@@ -26,7 +31,7 @@
*
* @hide
*/
-public final class DistanceMeasurement {
+public final class DistanceMeasurement implements Parcelable {
private final double mMeters;
private final double mErrorMeters;
private final double mConfidenceLevel;
@@ -70,6 +75,61 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof DistanceMeasurement) {
+ DistanceMeasurement other = (DistanceMeasurement) obj;
+ return mMeters == other.getMeters()
+ && mErrorMeters == other.getErrorMeters()
+ && mConfidenceLevel == other.getConfidenceLevel();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mMeters, mErrorMeters, mConfidenceLevel);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeDouble(mMeters);
+ dest.writeDouble(mErrorMeters);
+ dest.writeDouble(mConfidenceLevel);
+ }
+
+ public static final @android.annotation.NonNull Creator<DistanceMeasurement> CREATOR =
+ new Creator<DistanceMeasurement>() {
+ @Override
+ public DistanceMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setMeters(in.readDouble());
+ builder.setErrorMeters(in.readDouble());
+ builder.setConfidenceLevel(in.readDouble());
+ return builder.build();
+ }
+
+ @Override
+ public DistanceMeasurement[] newArray(int size) {
+ return new DistanceMeasurement[size];
+ }
+ };
+
+ /**
* Builder to get a {@link DistanceMeasurement} object.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingMeasurement.java b/core/java/android/uwb/RangingMeasurement.java
index 33a34e3..f1c3162 100644
--- a/core/java/android/uwb/RangingMeasurement.java
+++ b/core/java/android/uwb/RangingMeasurement.java
@@ -20,17 +20,20 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.SystemClock;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Representation of a ranging measurement between the local device and a remote device
*
* @hide
*/
-public final class RangingMeasurement {
+public final class RangingMeasurement implements Parcelable {
private final UwbAddress mRemoteDeviceAddress;
private final @Status int mStatus;
private final long mElapsedRealtimeNanos;
@@ -128,6 +131,71 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof RangingMeasurement) {
+ RangingMeasurement other = (RangingMeasurement) obj;
+ return mRemoteDeviceAddress.equals(other.getRemoteDeviceAddress())
+ && mStatus == other.getStatus()
+ && mElapsedRealtimeNanos == other.getElapsedRealtimeNanos()
+ && mDistanceMeasurement.equals(other.getDistance())
+ && mAngleOfArrivalMeasurement.equals(other.getAngleOfArrival());
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
+ mDistanceMeasurement, mAngleOfArrivalMeasurement);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mRemoteDeviceAddress, flags);
+ dest.writeInt(mStatus);
+ dest.writeLong(mElapsedRealtimeNanos);
+ dest.writeParcelable(mDistanceMeasurement, flags);
+ dest.writeParcelable(mAngleOfArrivalMeasurement, flags);
+ }
+
+ public static final @android.annotation.NonNull Creator<RangingMeasurement> CREATOR =
+ new Creator<RangingMeasurement>() {
+ @Override
+ public RangingMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setRemoteDeviceAddress(
+ in.readParcelable(UwbAddress.class.getClassLoader()));
+ builder.setStatus(in.readInt());
+ builder.setElapsedRealtimeNanos(in.readLong());
+ builder.setDistanceMeasurement(
+ in.readParcelable(DistanceMeasurement.class.getClassLoader()));
+ builder.setAngleOfArrivalMeasurement(
+ in.readParcelable(AngleOfArrivalMeasurement.class.getClassLoader()));
+ return builder.build();
+ }
+
+ @Override
+ public RangingMeasurement[] newArray(int size) {
+ return new RangingMeasurement[size];
+ }
+ };
+
+ /**
* Builder for a {@link RangingMeasurement} object.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingParams.java b/core/java/android/uwb/RangingParams.java
index a50de3e6..f23d9ed 100644
--- a/core/java/android/uwb/RangingParams.java
+++ b/core/java/android/uwb/RangingParams.java
@@ -19,15 +19,18 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.util.Duration;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -36,7 +39,7 @@
*
* @hide
*/
-public final class RangingParams {
+public final class RangingParams implements Parcelable {
private final boolean mIsInitiator;
private final boolean mIsController;
private final Duration mSamplePeriod;
@@ -200,6 +203,99 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof RangingParams) {
+ RangingParams other = (RangingParams) obj;
+
+ return mIsInitiator == other.mIsInitiator
+ && mIsController == other.mIsController
+ && mSamplePeriod.equals(other.mSamplePeriod)
+ && mLocalDeviceAddress.equals(other.mLocalDeviceAddress)
+ && mRemoteDeviceAddresses.equals(other.mRemoteDeviceAddresses)
+ && mChannelNumber == other.mChannelNumber
+ && mTransmitPreambleCodeIndex == other.mTransmitPreambleCodeIndex
+ && mReceivePreambleCodeIndex == other.mReceivePreambleCodeIndex
+ && mStsPhyPacketType == other.mStsPhyPacketType
+ && mSpecificationParameters.size() == other.mSpecificationParameters.size()
+ && mSpecificationParameters.kindofEquals(other.mSpecificationParameters);
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIsInitiator, mIsController, mSamplePeriod, mLocalDeviceAddress,
+ mRemoteDeviceAddresses, mChannelNumber, mTransmitPreambleCodeIndex,
+ mReceivePreambleCodeIndex, mStsPhyPacketType, mSpecificationParameters);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mIsInitiator);
+ dest.writeBoolean(mIsController);
+ dest.writeLong(mSamplePeriod.getSeconds());
+ dest.writeInt(mSamplePeriod.getNano());
+ dest.writeParcelable(mLocalDeviceAddress, flags);
+
+ UwbAddress[] remoteAddresses = new UwbAddress[mRemoteDeviceAddresses.size()];
+ mRemoteDeviceAddresses.toArray(remoteAddresses);
+ dest.writeParcelableArray(remoteAddresses, flags);
+
+ dest.writeInt(mChannelNumber);
+ dest.writeInt(mTransmitPreambleCodeIndex);
+ dest.writeInt(mReceivePreambleCodeIndex);
+ dest.writeInt(mStsPhyPacketType);
+ dest.writePersistableBundle(mSpecificationParameters);
+ }
+
+ public static final @android.annotation.NonNull Creator<RangingParams> CREATOR =
+ new Creator<RangingParams>() {
+ @Override
+ public RangingParams createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setIsInitiator(in.readBoolean());
+ builder.setIsController(in.readBoolean());
+ builder.setSamplePeriod(Duration.ofSeconds(in.readLong(), in.readInt()));
+ builder.setLocalDeviceAddress(
+ in.readParcelable(UwbAddress.class.getClassLoader()));
+
+ UwbAddress[] remoteAddresses =
+ in.readParcelableArray(null, UwbAddress.class);
+ for (UwbAddress remoteAddress : remoteAddresses) {
+ builder.addRemoteDeviceAddress(remoteAddress);
+ }
+
+ builder.setChannelNumber(in.readInt());
+ builder.setTransmitPreambleCodeIndex(in.readInt());
+ builder.setReceivePreambleCodeIndex(in.readInt());
+ builder.setStsPhPacketType(in.readInt());
+ builder.setSpecificationParameters(in.readPersistableBundle());
+
+ return builder.build();
+ }
+
+ @Override
+ public RangingParams[] newArray(int size) {
+ return new RangingParams[size];
+ }
+ };
+
+ /**
* Builder class for {@link RangingParams}.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingReport.java b/core/java/android/uwb/RangingReport.java
index 5aca12a..45180bf 100644
--- a/core/java/android/uwb/RangingReport.java
+++ b/core/java/android/uwb/RangingReport.java
@@ -17,16 +17,20 @@
package android.uwb;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* This class contains the UWB ranging data
*
* @hide
*/
-public final class RangingReport {
+public final class RangingReport implements Parcelable {
private final List<RangingMeasurement> mRangingMeasurements;
private RangingReport(@NonNull List<RangingMeasurement> rangingMeasurements) {
@@ -49,6 +53,56 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof RangingReport) {
+ RangingReport other = (RangingReport) obj;
+ return mRangingMeasurements.equals(other.getMeasurements());
+ }
+
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRangingMeasurements);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedList(mRangingMeasurements);
+ }
+
+ public static final @android.annotation.NonNull Creator<RangingReport> CREATOR =
+ new Creator<RangingReport>() {
+ @Override
+ public RangingReport createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.addMeasurements(in.createTypedArrayList(RangingMeasurement.CREATOR));
+ return builder.build();
+ }
+
+ @Override
+ public RangingReport[] newArray(int size) {
+ return new RangingReport[size];
+ }
+ };
+
+ /**
* Builder for {@link RangingReport} object
*/
public static final class Builder {
diff --git a/core/java/android/uwb/TEST_MAPPING b/core/java/android/uwb/TEST_MAPPING
new file mode 100644
index 0000000..9e50bd6
--- /dev/null
+++ b/core/java/android/uwb/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "UwbManagerTests"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/java/android/uwb/UwbAddress.java b/core/java/android/uwb/UwbAddress.java
index 48fcb10e..828324c 100644
--- a/core/java/android/uwb/UwbAddress.java
+++ b/core/java/android/uwb/UwbAddress.java
@@ -18,16 +18,26 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
/**
* A class representing a UWB address
*
* @hide
*/
-public final class UwbAddress {
+public final class UwbAddress implements Parcelable {
public static final int SHORT_ADDRESS_BYTE_LENGTH = 2;
public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8;
+ private final byte[] mAddressBytes;
+
+ private UwbAddress(byte[] address) {
+ mAddressBytes = address;
+ }
+
/**
* Create a {@link UwbAddress} from a byte array.
*
@@ -37,12 +47,16 @@
*
* @param address a byte array to convert to a {@link UwbAddress}
* @return a {@link UwbAddress} created from the input byte array
- * @throw IllegableArumentException when the length is not one of
+ * @throws IllegalArgumentException when the length is not one of
* {@link #SHORT_ADDRESS_BYTE_LENGTH} or {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes
*/
@NonNull
- public static UwbAddress fromBytes(byte[] address) throws IllegalArgumentException {
- throw new UnsupportedOperationException();
+ public static UwbAddress fromBytes(@NonNull byte[] address) throws IllegalArgumentException {
+ if (address.length != SHORT_ADDRESS_BYTE_LENGTH
+ && address.length != EXTENDED_ADDRESS_BYTE_LENGTH) {
+ throw new IllegalArgumentException("Invalid UwbAddress length " + address.length);
+ }
+ return new UwbAddress(address);
}
/**
@@ -52,7 +66,7 @@
*/
@NonNull
public byte[] toBytes() {
- throw new UnsupportedOperationException();
+ return mAddressBytes;
}
/**
@@ -61,22 +75,55 @@
* {@link #EXTENDED_ADDRESS_BYTE_LENGTH}.
*/
public int size() {
- throw new UnsupportedOperationException();
+ return mAddressBytes.length;
}
@NonNull
@Override
public String toString() {
- throw new UnsupportedOperationException();
+ StringBuilder builder = new StringBuilder("0x");
+ for (byte addressByte : mAddressBytes) {
+ builder.append(String.format("%02X", addressByte));
+ }
+ return builder.toString();
}
@Override
public boolean equals(@Nullable Object obj) {
- throw new UnsupportedOperationException();
+ if (obj instanceof UwbAddress) {
+ return Arrays.equals(mAddressBytes, ((UwbAddress) obj).toBytes());
+ }
+ return false;
}
@Override
public int hashCode() {
- throw new UnsupportedOperationException();
+ return Arrays.hashCode(mAddressBytes);
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mAddressBytes.length);
+ dest.writeByteArray(mAddressBytes);
+ }
+
+ public static final @android.annotation.NonNull Creator<UwbAddress> CREATOR =
+ new Creator<UwbAddress>() {
+ @Override
+ public UwbAddress createFromParcel(Parcel in) {
+ byte[] address = new byte[in.readInt()];
+ in.readByteArray(address);
+ return UwbAddress.fromBytes(address);
+ }
+
+ @Override
+ public UwbAddress[] newArray(int size) {
+ return new UwbAddress[size];
+ }
+ };
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c383bc7..985829f 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1134,15 +1134,14 @@
if (invokeCallback) {
control.cancel();
}
+ boolean stateChanged = false;
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == control) {
mRunningAnimations.remove(i);
ArraySet<Integer> types = toInternalType(control.getTypes());
for (int j = types.size() - 1; j >= 0; j--) {
- if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
- mHost.notifyInsetsChanged();
- }
+ stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
if (invokeCallback && runningAnimation.startDispatched) {
dispatchAnimationEnd(runningAnimation.runner.getAnimation());
@@ -1150,6 +1149,10 @@
break;
}
}
+ if (stateChanged) {
+ mHost.notifyInsetsChanged();
+ updateRequestedState();
+ }
}
private void applyLocalVisibilityOverride() {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4548f3a..2b2bf8d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2792,6 +2792,7 @@
<item>power</item>
<item>restart</item>
<item>logout</item>
+ <item>screenshot</item>
<item>bugreport</item>
</string-array>
@@ -3506,6 +3507,7 @@
mode -->
<string-array translatable="false" name="config_priorityOnlyDndExemptPackages">
<item>com.android.dialer</item>
+ <item>com.android.server.telecom</item>
<item>com.android.systemui</item>
<item>android</item>
</string-array>
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 801cd4d..48695aa 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -27,6 +27,7 @@
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -742,6 +743,20 @@
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(newState.getSource(ITYPE_IME),
mTestHost.getModifiedState().peekSource(ITYPE_IME));
+
+ // The modified frames cannot be updated if there is an animation.
+ mController.onControlsChanged(createSingletonControl(ITYPE_NAVIGATION_BAR));
+ mController.hide(navigationBars());
+ newState = new InsetsState(mController.getState(), true /* copySource */);
+ newState.getSource(ITYPE_NAVIGATION_BAR).getFrame().top--;
+ mController.onStateChanged(newState);
+ assertNotEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
+
+ // The modified frames can be updated while the animation is done.
+ mController.cancelExistingAnimations();
+ assertEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
});
}
diff --git a/core/tests/uwbtests/Android.bp b/core/tests/uwbtests/Android.bp
new file mode 100644
index 0000000..c41c346
--- /dev/null
+++ b/core/tests/uwbtests/Android.bp
@@ -0,0 +1,28 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "UwbManagerTests",
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ ],
+ libs: [
+ "android.test.runner",
+ ],
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/uwbtests/AndroidManifest.xml b/core/tests/uwbtests/AndroidManifest.xml
new file mode 100644
index 0000000..dc991ff
--- /dev/null
+++ b/core/tests/uwbtests/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.uwb">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- This is a self-instrumenting test package. -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.uwb"
+ android:label="UWB Manager Tests">
+ </instrumentation>
+
+</manifest>
+
diff --git a/core/tests/uwbtests/AndroidTest.xml b/core/tests/uwbtests/AndroidTest.xml
new file mode 100644
index 0000000..ff4b668
--- /dev/null
+++ b/core/tests/uwbtests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for UWB Manager test cases">
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-suite-tag" value="apct-instrumentation"/>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="UwbManagerTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="UwbManagerTests"/>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.uwb" />
+ <option name="hidden-api-checks" value="false"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java
new file mode 100644
index 0000000..7769c28
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link AngleMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AngleMeasurementTest {
+ private static final double EPSILON = 0.00000000001;
+
+ @Test
+ public void testBuilder() {
+ double radians = 0.1234;
+ double errorRadians = 0.5678;
+ double confidence = 0.5;
+
+ AngleMeasurement.Builder builder = new AngleMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setRadians(radians);
+ tryBuild(builder, false);
+
+ builder.setErrorRadians(errorRadians);
+ tryBuild(builder, false);
+
+ builder.setConfidenceLevel(confidence);
+ AngleMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(measurement.getRadians(), radians, 0);
+ assertEquals(measurement.getErrorRadians(), errorRadians, 0);
+ assertEquals(measurement.getConfidenceLevel(), confidence, 0);
+ }
+
+ private AngleMeasurement tryBuild(AngleMeasurement.Builder builder, boolean expectSuccess) {
+ AngleMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected AngleMeasurement.Builder.build() to fail, but it succeeded");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected AngleMeasurement.Builder.build() to succeed, but it failed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ AngleMeasurement measurement = UwbTestUtils.getAngleMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ AngleMeasurement fromParcel = AngleMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
new file mode 100644
index 0000000..077b08f
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link AngleOfArrivalMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AngleOfArrivalMeasurementTest {
+
+ @Test
+ public void testBuilder() {
+ AngleMeasurement azimuth = UwbTestUtils.getAngleMeasurement();
+ AngleMeasurement altitude = UwbTestUtils.getAngleMeasurement();
+
+ AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setAltitudeAngleMeasurement(altitude);
+ tryBuild(builder, false);
+
+ builder.setAzimuthAngleMeasurement(azimuth);
+ AngleOfArrivalMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(azimuth, measurement.getAzimuth());
+ assertEquals(altitude, measurement.getAltitude());
+ }
+
+ private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) {
+ return new AngleMeasurement.Builder()
+ .setRadians(radian)
+ .setErrorRadians(error)
+ .setConfidenceLevel(confidence)
+ .build();
+ }
+
+ private AngleOfArrivalMeasurement tryBuild(AngleOfArrivalMeasurement.Builder builder,
+ boolean expectSuccess) {
+ AngleOfArrivalMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected AngleOfArrivalMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected AngleOfArrivalMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ AngleOfArrivalMeasurement measurement = UwbTestUtils.getAngleOfArrivalMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ AngleOfArrivalMeasurement fromParcel =
+ AngleOfArrivalMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java
new file mode 100644
index 0000000..439c884
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link DistanceMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DistanceMeasurementTest {
+ private static final double EPSILON = 0.00000000001;
+
+ @Test
+ public void testBuilder() {
+ double meters = 0.12;
+ double error = 0.54;
+ double confidence = 0.99;
+
+ DistanceMeasurement.Builder builder = new DistanceMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setMeters(meters);
+ tryBuild(builder, false);
+
+ builder.setErrorMeters(error);
+ tryBuild(builder, false);
+
+ builder.setConfidenceLevel(confidence);
+ DistanceMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(meters, measurement.getMeters(), 0);
+ assertEquals(error, measurement.getErrorMeters(), 0);
+ assertEquals(confidence, measurement.getConfidenceLevel(), 0);
+ }
+
+ private DistanceMeasurement tryBuild(DistanceMeasurement.Builder builder,
+ boolean expectSuccess) {
+ DistanceMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ DistanceMeasurement measurement = UwbTestUtils.getDistanceMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ DistanceMeasurement fromParcel =
+ DistanceMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java
new file mode 100644
index 0000000..a7559d8
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+import android.os.SystemClock;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link RangingMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangingMeasurementTest {
+
+ @Test
+ public void testBuilder() {
+ int status = RangingMeasurement.RANGING_STATUS_SUCCESS;
+ UwbAddress address = UwbTestUtils.getUwbAddress(false);
+ long time = SystemClock.elapsedRealtimeNanos();
+ AngleOfArrivalMeasurement angleMeasurement = UwbTestUtils.getAngleOfArrivalMeasurement();
+ DistanceMeasurement distanceMeasurement = UwbTestUtils.getDistanceMeasurement();
+
+ RangingMeasurement.Builder builder = new RangingMeasurement.Builder();
+
+ builder.setStatus(status);
+ tryBuild(builder, false);
+
+ builder.setElapsedRealtimeNanos(time);
+ tryBuild(builder, false);
+
+ builder.setAngleOfArrivalMeasurement(angleMeasurement);
+ tryBuild(builder, false);
+
+ builder.setDistanceMeasurement(distanceMeasurement);
+ tryBuild(builder, false);
+
+ builder.setRemoteDeviceAddress(address);
+ RangingMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(status, measurement.getStatus());
+ assertEquals(address, measurement.getRemoteDeviceAddress());
+ assertEquals(time, measurement.getElapsedRealtimeNanos());
+ assertEquals(angleMeasurement, measurement.getAngleOfArrival());
+ assertEquals(distanceMeasurement, measurement.getDistance());
+ }
+
+ private RangingMeasurement tryBuild(RangingMeasurement.Builder builder,
+ boolean expectSuccess) {
+ RangingMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected RangingMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ RangingMeasurement measurement = UwbTestUtils.getRangingMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ RangingMeasurement fromParcel = RangingMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingParamsTest.java b/core/tests/uwbtests/src/android/uwb/RangingParamsTest.java
new file mode 100644
index 0000000..8095c99
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/RangingParamsTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.PersistableBundle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+
+/**
+ * Test of {@link RangingParams}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangingParamsTest {
+
+ @Test
+ public void testParams_Build() {
+ UwbAddress local = UwbAddress.fromBytes(new byte[] {(byte) 0xA0, (byte) 0x57});
+ UwbAddress remote = UwbAddress.fromBytes(new byte[] {(byte) 0x4D, (byte) 0x8C});
+ int channel = 9;
+ int rxPreamble = 16;
+ int txPreamble = 21;
+ boolean isController = true;
+ boolean isInitiator = false;
+ @RangingParams.StsPhyPacketType int stsPhyType = RangingParams.STS_PHY_PACKET_TYPE_SP2;
+ Duration samplePeriod = Duration.ofSeconds(1, 234);
+ PersistableBundle specParams = new PersistableBundle();
+ specParams.putString("protocol", "some_protocol");
+
+ RangingParams params = new RangingParams.Builder()
+ .setChannelNumber(channel)
+ .setReceivePreambleCodeIndex(rxPreamble)
+ .setTransmitPreambleCodeIndex(txPreamble)
+ .setLocalDeviceAddress(local)
+ .addRemoteDeviceAddress(remote)
+ .setIsController(isController)
+ .setIsInitiator(isInitiator)
+ .setSamplePeriod(samplePeriod)
+ .setStsPhPacketType(stsPhyType)
+ .setSpecificationParameters(specParams)
+ .build();
+
+ assertEquals(params.getLocalDeviceAddress(), local);
+ assertEquals(params.getRemoteDeviceAddresses().size(), 1);
+ assertEquals(params.getRemoteDeviceAddresses().get(0), remote);
+ assertEquals(params.getChannelNumber(), channel);
+ assertEquals(params.isController(), isController);
+ assertEquals(params.isInitiator(), isInitiator);
+ assertEquals(params.getRxPreambleIndex(), rxPreamble);
+ assertEquals(params.getTxPreambleIndex(), txPreamble);
+ assertEquals(params.getStsPhyPacketType(), stsPhyType);
+ assertEquals(params.getSamplingPeriod(), samplePeriod);
+ assertTrue(params.getSpecificationParameters().kindofEquals(specParams));
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ RangingParams params = new RangingParams.Builder()
+ .setChannelNumber(9)
+ .setReceivePreambleCodeIndex(16)
+ .setTransmitPreambleCodeIndex(21)
+ .setLocalDeviceAddress(UwbTestUtils.getUwbAddress(false))
+ .addRemoteDeviceAddress(UwbTestUtils.getUwbAddress(true))
+ .setIsController(false)
+ .setIsInitiator(true)
+ .setSamplePeriod(Duration.ofSeconds(2))
+ .setStsPhPacketType(RangingParams.STS_PHY_PACKET_TYPE_SP1)
+ .build();
+ params.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ RangingParams fromParcel = RangingParams.CREATOR.createFromParcel(parcel);
+ assertEquals(params, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingReportTest.java b/core/tests/uwbtests/src/android/uwb/RangingReportTest.java
new file mode 100644
index 0000000..64c48ba
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/RangingReportTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Test of {@link RangingReport}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangingReportTest {
+
+ @Test
+ public void testBuilder() {
+ List<RangingMeasurement> measurements = UwbTestUtils.getRangingMeasurements(5);
+
+ RangingReport.Builder builder = new RangingReport.Builder();
+ builder.addMeasurements(measurements);
+ RangingReport report = tryBuild(builder, true);
+ verifyMeasurementsEqual(measurements, report.getMeasurements());
+
+
+ builder = new RangingReport.Builder();
+ for (RangingMeasurement measurement : measurements) {
+ builder.addMeasurement(measurement);
+ }
+ report = tryBuild(builder, true);
+ verifyMeasurementsEqual(measurements, report.getMeasurements());
+ }
+
+ private void verifyMeasurementsEqual(List<RangingMeasurement> expected,
+ List<RangingMeasurement> actual) {
+ assertEquals(expected.size(), actual.size());
+ for (int i = 0; i < expected.size(); i++) {
+ assertEquals(expected.get(i), actual.get(i));
+ }
+ }
+
+ private RangingReport tryBuild(RangingReport.Builder builder,
+ boolean expectSuccess) {
+ RangingReport report = null;
+ try {
+ report = builder.build();
+ if (!expectSuccess) {
+ fail("Expected RangingReport.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected RangingReport.Builder.build() to succeed");
+ }
+ }
+ return report;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ RangingReport report = UwbTestUtils.getRangingReports(5);
+ report.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ RangingReport fromParcel = RangingReport.CREATOR.createFromParcel(parcel);
+ assertEquals(report, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java b/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java
new file mode 100644
index 0000000..ccc88a9
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link UwbAddress}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class UwbAddressTest {
+
+ @Test
+ public void testFromBytes_Short() {
+ runFromBytes(UwbAddress.SHORT_ADDRESS_BYTE_LENGTH);
+ }
+
+ @Test
+ public void testFromBytes_Extended() {
+ runFromBytes(UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH);
+ }
+
+ private void runFromBytes(int len) {
+ byte[] addressBytes = getByteArray(len);
+ UwbAddress address = UwbAddress.fromBytes(addressBytes);
+ assertEquals(address.size(), len);
+ assertEquals(addressBytes, address.toBytes());
+ }
+
+ private byte[] getByteArray(int len) {
+ byte[] res = new byte[len];
+ for (int i = 0; i < len; i++) {
+ res[i] = (byte) i;
+ }
+ return res;
+ }
+
+ @Test
+ public void testParcel_Short() {
+ runParcel(true);
+ }
+
+ @Test
+ public void testParcel_Extended() {
+ runParcel(false);
+ }
+
+ private void runParcel(boolean useShortAddress) {
+ Parcel parcel = Parcel.obtain();
+ UwbAddress address = UwbTestUtils.getUwbAddress(useShortAddress);
+ address.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ UwbAddress fromParcel = UwbAddress.CREATOR.createFromParcel(parcel);
+ assertEquals(address, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
new file mode 100644
index 0000000..62e0b62
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import android.os.SystemClock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UwbTestUtils {
+ private UwbTestUtils() {}
+
+ public static AngleMeasurement getAngleMeasurement() {
+ return new AngleMeasurement.Builder()
+ .setRadians(getDoubleInRange(-Math.PI, Math.PI))
+ .setErrorRadians(getDoubleInRange(0, Math.PI))
+ .setConfidenceLevel(getDoubleInRange(0, 1))
+ .build();
+ }
+
+ public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
+ return new AngleOfArrivalMeasurement.Builder()
+ .setAltitudeAngleMeasurement(getAngleMeasurement())
+ .setAzimuthAngleMeasurement(getAngleMeasurement())
+ .build();
+ }
+
+ public static DistanceMeasurement getDistanceMeasurement() {
+ return new DistanceMeasurement.Builder()
+ .setMeters(getDoubleInRange(0, 100))
+ .setErrorMeters(getDoubleInRange(0, 10))
+ .setConfidenceLevel(getDoubleInRange(0, 1))
+ .build();
+ }
+
+ public static RangingMeasurement getRangingMeasurement() {
+ return getRangingMeasurement(getUwbAddress(false));
+ }
+
+ public static RangingMeasurement getRangingMeasurement(UwbAddress address) {
+ return new RangingMeasurement.Builder()
+ .setDistanceMeasurement(getDistanceMeasurement())
+ .setAngleOfArrivalMeasurement(getAngleOfArrivalMeasurement())
+ .setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos())
+ .setRemoteDeviceAddress(address != null ? address : getUwbAddress(false))
+ .setStatus(RangingMeasurement.RANGING_STATUS_SUCCESS)
+ .build();
+ }
+
+ public static List<RangingMeasurement> getRangingMeasurements(int num) {
+ List<RangingMeasurement> result = new ArrayList<>();
+ for (int i = 0; i < num; i++) {
+ result.add(getRangingMeasurement());
+ }
+ return result;
+ }
+
+ public static RangingReport getRangingReports(int numMeasurements) {
+ RangingReport.Builder builder = new RangingReport.Builder();
+ for (int i = 0; i < numMeasurements; i++) {
+ builder.addMeasurement(getRangingMeasurement());
+ }
+ return builder.build();
+ }
+
+ private static double getDoubleInRange(double min, double max) {
+ return min + (max - min) * Math.random();
+ }
+
+ public static UwbAddress getUwbAddress(boolean isShortAddress) {
+ byte[] addressBytes = new byte[isShortAddress ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH :
+ UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH];
+ for (int i = 0; i < addressBytes.length; i++) {
+ addressBytes[i] = (byte) getDoubleInRange(1, 255);
+ }
+ return UwbAddress.fromBytes(addressBytes);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index ef51abb..2702bc4 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -19,6 +19,7 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS;
import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
@@ -547,7 +548,7 @@
if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
return false;
}
- return true;
+ return action.shouldShow();
}
/**
@@ -962,6 +963,8 @@
@VisibleForTesting
class ScreenshotAction extends SinglePressAction implements LongPressAction {
+ final String KEY_SYSTEM_NAV_2BUTTONS = "system_nav_2buttons";
+
public ScreenshotAction() {
super(R.drawable.ic_screenshot, R.string.global_action_screenshot);
}
@@ -994,6 +997,19 @@
}
@Override
+ public boolean shouldShow() {
+ // Include screenshot in power menu for legacy nav because it is not accessible
+ // through Recents in that mode
+ return is2ButtonNavigationEnabled();
+ }
+
+ boolean is2ButtonNavigationEnabled() {
+ return NAV_BAR_MODE_2BUTTON == mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_navBarInteractionMode);
+ }
+
+
+ @Override
public boolean onLongPress() {
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS)) {
mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS);
@@ -1616,6 +1632,10 @@
* @return
*/
CharSequence getMessage();
+
+ default boolean shouldShow() {
+ return true;
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index bc03ca6..077c7aa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.telephony.SubscriptionManager;
@@ -230,7 +231,8 @@
@Override
public boolean isAvailable() {
- return mController.hasMobileDataFeature();
+ return mController.hasMobileDataFeature()
+ && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM;
}
private static final class CallbackInfo {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index ac8c671..5e2e7c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -49,6 +49,7 @@
import android.util.FeatureFlagUtils;
import android.view.IWindowManager;
import android.view.View;
+import android.view.WindowManagerPolicyConstants;
import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
@@ -241,6 +242,28 @@
verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS);
}
+ @Test
+ public void testShouldShowScreenshot() {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.integer.config_navBarInteractionMode,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON);
+
+ GlobalActionsDialog.ScreenshotAction screenshotAction =
+ mGlobalActionsDialog.makeScreenshotActionForTesting();
+ assertThat(screenshotAction.shouldShow()).isTrue();
+ }
+
+ @Test
+ public void testShouldNotShowScreenshot() {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.integer.config_navBarInteractionMode,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON);
+
+ GlobalActionsDialog.ScreenshotAction screenshotAction =
+ mGlobalActionsDialog.makeScreenshotActionForTesting();
+ assertThat(screenshotAction.shouldShow()).isFalse();
+ }
+
private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) {
mTestableLooper.processAllMessages();
verify(mUiEventLogger, times(1))
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 22423fe..a992aa6 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1105,23 +1105,26 @@
intentFilter.addAction(Intent.ACTION_USER_ADDED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiverAsUser(
+
+ final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+ userAllContext.registerReceiver(
mIntentReceiver,
- UserHandle.ALL,
intentFilter,
null /* broadcastPermission */,
mHandler);
- mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
- new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
+ mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
+ mUserPresentReceiver,
+ new IntentFilter(Intent.ACTION_USER_PRESENT),
+ null /* broadcastPermission */,
+ null /* scheduler */);
// Listen to package add and removal events for all users.
intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
- mContext.registerReceiverAsUser(
+ userAllContext.registerReceiver(
mIntentReceiver,
- UserHandle.ALL,
intentFilter,
null /* broadcastPermission */,
mHandler);
@@ -1129,8 +1132,8 @@
// Listen to lockdown VPN reset.
intentFilter = new IntentFilter();
intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
- mContext.registerReceiverAsUser(
- mIntentReceiver, UserHandle.ALL, intentFilter, NETWORK_STACK, mHandler);
+ userAllContext.registerReceiver(
+ mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
try {
mNMS.registerObserver(mDataActivityObserver);
@@ -5259,7 +5262,9 @@
// Try creating lockdown tracker, since user present usually means
// unlocked keystore.
updateLockdownVpn();
- mContext.unregisterReceiver(this);
+ // Use the same context that registered receiver before to unregister it. Because use
+ // different context to unregister receiver will cause exception.
+ context.unregisterReceiver(this);
}
};
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index d548871..17828a0 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -95,7 +95,11 @@
private static final boolean DBG = false;
+ // This context is for the current user.
private final Context mContext;
+ // This context is for all users, so register a BroadcastReceiver which can receive intents from
+ // all users.
+ private final Context mUserAllContext;
private final Handler mHandler;
private final Clock mClock;
private final Dependencies mDeps;
@@ -132,6 +136,7 @@
public MultipathPolicyTracker(Context ctx, Handler handler, Dependencies deps) {
mContext = ctx;
+ mUserAllContext = ctx.createContextAsUser(UserHandle.ALL, 0 /* flags */);
mHandler = handler;
mClock = deps.getClock();
mDeps = deps;
@@ -155,8 +160,8 @@
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiverAsUser(
- mConfigChangeReceiver, UserHandle.ALL, intentFilter, null, mHandler);
+ mUserAllContext.registerReceiver(
+ mConfigChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler);
}
public void shutdown() {
@@ -167,7 +172,7 @@
}
mMultipathTrackers.clear();
mResolver.unregisterContentObserver(mSettingsObserver);
- mContext.unregisterReceiver(mConfigChangeReceiver);
+ mUserAllContext.unregisterReceiver(mConfigChangeReceiver);
}
// Called on an arbitrary binder thread.
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 1a83272..9e43b54 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -865,7 +865,7 @@
Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
serviceIntent.setPackage(alwaysOnPackage);
try {
- return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserId)) != null;
+ return mUserIdContext.startService(serviceIntent) != null;
} catch (RuntimeException e) {
Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e);
return false;
@@ -1036,20 +1036,21 @@
final long token = Binder.clearCallingIdentity();
try {
- final int[] toChange;
+ final String[] toChange;
// Clear all AppOps if the app is being unauthorized.
switch (vpnType) {
case VpnManager.TYPE_VPN_NONE:
- toChange = new int[] {
- AppOpsManager.OP_ACTIVATE_VPN, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN
+ toChange = new String[] {
+ AppOpsManager.OPSTR_ACTIVATE_VPN,
+ AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN
};
break;
case VpnManager.TYPE_VPN_PLATFORM:
- toChange = new int[] {AppOpsManager.OP_ACTIVATE_PLATFORM_VPN};
+ toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN};
break;
case VpnManager.TYPE_VPN_SERVICE:
- toChange = new int[] {AppOpsManager.OP_ACTIVATE_VPN};
+ toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_VPN};
break;
default:
Log.wtf(TAG, "Unrecognized VPN type while granting authorization");
@@ -1058,9 +1059,9 @@
final AppOpsManager appOpMgr =
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
- for (final int appOp : toChange) {
+ for (final String appOpStr : toChange) {
appOpMgr.setMode(
- appOp,
+ appOpStr,
uid,
packageName,
vpnType == VpnManager.TYPE_VPN_NONE
@@ -1086,21 +1087,22 @@
}
}
- private static boolean doesPackageHaveAppop(Context context, String packageName, int appop) {
+ private static boolean doesPackageHaveAppop(Context context, String packageName,
+ String appOpStr) {
final AppOpsManager appOps =
(AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
// Verify that the caller matches the given package and has the required permission.
- return appOps.noteOpNoThrow(appop, Binder.getCallingUid(), packageName)
- == AppOpsManager.MODE_ALLOWED;
+ return appOps.noteOpNoThrow(appOpStr, Binder.getCallingUid(), packageName,
+ null /* attributionTag */, null /* message */) == AppOpsManager.MODE_ALLOWED;
}
private static boolean isVpnServicePreConsented(Context context, String packageName) {
- return doesPackageHaveAppop(context, packageName, AppOpsManager.OP_ACTIVATE_VPN);
+ return doesPackageHaveAppop(context, packageName, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
private static boolean isVpnProfilePreConsented(Context context, String packageName) {
- return doesPackageHaveAppop(context, packageName, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN)
+ return doesPackageHaveAppop(context, packageName, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN)
|| isVpnServicePreConsented(context, packageName);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 611b8c6..ab289ea 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -708,17 +708,17 @@
private byte[] getSupportedShortAudioDescriptorsFromConfig(
List<DeviceConfig> deviceConfig, @AudioCodec int[] audioFormatCodes) {
DeviceConfig deviceConfigToUse = null;
+ String audioDeviceName = SystemProperties.get(
+ Constants.PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT,
+ "VX_AUDIO_DEVICE_IN_HDMI_ARC");
for (DeviceConfig device : deviceConfig) {
- // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
- if (device.name.equals("VX_AUDIO_DEVICE_IN_HDMI_ARC")) {
+ if (device.name.equals(audioDeviceName)) {
deviceConfigToUse = device;
break;
}
}
if (deviceConfigToUse == null) {
- // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
- Slog.w(TAG, "sadConfig.xml does not have required device info for "
- + "VX_AUDIO_DEVICE_IN_HDMI_ARC");
+ Slog.w(TAG, "sadConfig.xml does not have required device info for " + audioDeviceName);
return new byte[0];
}
HashMap<Integer, byte[]> map = new HashMap<>();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 2c0ddaf..804cc92 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1667,6 +1667,7 @@
if (avr == null) {
return;
}
+ setArcStatus(false);
// Seq #44.
removeAction(RequestArcInitiationAction.class);
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 72559b4..ddc5ef2 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -24,7 +24,6 @@
import android.Manifest;
import android.annotation.IntDef;
import android.app.AppOpsManager;
-import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -112,8 +111,7 @@
boolean hasCarrierPrivileges = tm != null &&
tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) ==
TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
- boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
- DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid);
final int appId = UserHandle.getAppId(callingUid);
if (hasCarrierPrivileges || isDeviceOwner
|| appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) {
@@ -128,8 +126,9 @@
return NetworkStatsAccess.Level.DEVICESUMMARY;
}
- boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
+ boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid)
+ || dpmi.isActiveDeviceOwner(callingUid));
if (isProfileOwner) {
// Apps with the AppOps permission, profile owners, and apps with the privileged
// permission can access data usage for all apps in this user/profile.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dac3252..3d63606 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4206,13 +4206,9 @@
Iterator<ResolveInfo> iter = matches.iterator();
while (iter.hasNext()) {
final ResolveInfo rInfo = iter.next();
- final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
- if (ps != null) {
- final PermissionsState permissionsState = ps.getPermissionsState();
- if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)
- || Build.IS_ENG) {
- continue;
- }
+ if (checkPermission(Manifest.permission.INSTALL_PACKAGES,
+ rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || Build.IS_ENG) {
+ continue;
}
iter.remove();
}
@@ -4388,8 +4384,24 @@
final int[] gids = (flags & PackageManager.GET_GIDS) == 0
? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
// Compute granted permissions only if package has requested permissions
- final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
+ Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
? Collections.emptySet() : permissionsState.getPermissions(userId);
+ if (state.instantApp) {
+ permissions = new ArraySet<>(permissions);
+ permissions.removeIf(permissionName -> {
+ BasePermission permission = mPermissionManager.getPermissionTEMP(
+ permissionName);
+ if (permission == null) {
+ return true;
+ }
+ if (!permission.isInstant()) {
+ EventLog.writeEvent(0x534e4554, "140256621", UserHandle.getUid(userId,
+ ps.appId), permissionName);
+ return true;
+ }
+ return false;
+ });
+ }
PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps);
@@ -8587,10 +8599,9 @@
private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageSetting ps,
String[] permissions, boolean[] tmp, int flags, int userId) {
int numMatch = 0;
- final PermissionsState permissionsState = ps.getPermissionsState();
for (int i=0; i<permissions.length; i++) {
final String permission = permissions[i];
- if (permissionsState.hasPermission(permission, userId)) {
+ if (checkPermission(permission, ps.name, userId) == PERMISSION_GRANTED) {
tmp[i] = true;
numMatch++;
} else {
@@ -19199,6 +19210,14 @@
final int flags = action.flags;
final boolean systemApp = isSystemApp(ps);
+ // We need to get the permission state before package state is (potentially) destroyed.
+ final SparseBooleanArray hadSuspendAppsPermission = new SparseBooleanArray();
+ // allUserHandles could be null, so call mUserManager.getUserIds() directly which is cached anyway.
+ for (int userId : mUserManager.getUserIds()) {
+ hadSuspendAppsPermission.put(userId, checkPermission(Manifest.permission.SUSPEND_APPS,
+ packageName, userId) == PERMISSION_GRANTED);
+ }
+
final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
@@ -19265,8 +19284,7 @@
affectedUserIds = resolveUserIds(userId);
}
for (final int affectedUserId : affectedUserIds) {
- if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS,
- affectedUserId)) {
+ if (hadSuspendAppsPermission.get(affectedUserId)) {
unsuspendForSuspendingPackage(packageName, affectedUserId);
removeAllDistractingPackageRestrictions(affectedUserId);
}
@@ -21036,8 +21054,8 @@
pkgSetting.setEnabled(newState, userId, callingPackage);
if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| newState == COMPONENT_ENABLED_STATE_DISABLED)
- && pkgSetting.getPermissionsState().hasPermission(
- Manifest.permission.SUSPEND_APPS, userId)) {
+ && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+ == PERMISSION_GRANTED) {
// This app should not generally be allowed to get disabled by the UI, but if it
// ever does, we don't want to end up with some of the user's apps permanently
// suspended.
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index b571a9c..bb5a953 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1060,7 +1060,9 @@
+ "; isStaged = " + session.isStaged()
+ "; isReady = " + session.isStagedSessionReady()
+ "; isApplied = " + session.isStagedSessionApplied()
- + "; isFailed = " + session.isStagedSessionFailed() + ";");
+ + "; isFailed = " + session.isStagedSessionFailed()
+ + "; errorMsg = " + session.getStagedSessionErrorMessage()
+ + ";");
}
private Intent parseIntentAndUser() throws URISyntaxException {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 0c96f59..33433db 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -605,13 +605,14 @@
// If checkpoint is supported, then we only resume sessions if we are in checkpointing
// mode. If not, we fail all sessions.
if (supportsCheckpoint() && !needsCheckpoint()) {
- String errorMsg = "Reverting back to safe state. Marking " + session.sessionId
- + " as failed";
- if (!TextUtils.isEmpty(mFailureReason)) {
- errorMsg = errorMsg + ": " + mFailureReason;
+ String revertMsg = "Reverting back to safe state. Marking "
+ + session.sessionId + " as failed.";
+ final String reasonForRevert = getReasonForRevert();
+ if (!TextUtils.isEmpty(reasonForRevert)) {
+ revertMsg += " Reason for revert: " + reasonForRevert;
}
- Slog.d(TAG, errorMsg);
- session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, errorMsg);
+ Slog.d(TAG, revertMsg);
+ session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, revertMsg);
return;
}
} catch (RemoteException e) {
@@ -715,6 +716,16 @@
}
}
+ private String getReasonForRevert() {
+ if (!TextUtils.isEmpty(mFailureReason)) {
+ return mFailureReason;
+ }
+ if (!TextUtils.isEmpty(mNativeFailureReason)) {
+ return "Session reverted due to crashing native process: " + mNativeFailureReason;
+ }
+ return "";
+ }
+
private List<String> findAPKsInDir(File stageDir) {
List<String> ret = new ArrayList<>();
if (stageDir != null && stageDir.exists()) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b79953e..cfbc77c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4578,15 +4578,6 @@
return false;
}
- // Check if the activity is on a sleeping display, and if it can turn it ON.
- if (getDisplay().isSleeping()) {
- final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn()
- || canShowWhenLocked() || containsDismissKeyguardWindow();
- if (!canTurnScreenOn) {
- return false;
- }
- }
-
// Now check whether it's really visible depending on Keyguard state, and update
// {@link ActivityStack} internal states.
// Inform the method if this activity is the top activity of this stack, but exclude the
@@ -4597,6 +4588,12 @@
final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
+ // Check if the activity is on a sleeping display, and if it can turn it ON.
+ // TODO(b/163993448): Do not make activity visible before display awake.
+ if (visibleIgnoringDisplayStatus && getDisplay().isSleeping()) {
+ return !mSetToSleep || canTurnScreenOn();
+ }
+
return visibleIgnoringDisplayStatus;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index e9768a2..2b785c5 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1704,8 +1704,9 @@
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
- if (shouldSleepActivities() && mLastNoHistoryActivity != null &&
- !mLastNoHistoryActivity.finishing) {
+ if (shouldSleepActivities() && mLastNoHistoryActivity != null
+ && !mLastNoHistoryActivity.finishing
+ && mLastNoHistoryActivity != next) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"no-history finish of " + mLastNoHistoryActivity + " on new resume");
mLastNoHistoryActivity.finishIfPossible("resume-no-history", false /* oomAdj */);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index b378621..35ccc43 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1481,9 +1481,10 @@
// anyone interested in this piece of information.
final ActivityStack homeStack = targetTask.getDisplayArea().getRootHomeTask();
final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null);
+ final ActivityRecord top = targetTask.getTopNonFinishingActivity();
+ final boolean visible = top != null && top.isVisible();
mService.getTaskChangeNotificationController().notifyActivityRestartAttempt(
- targetTask.getTaskInfo(), homeTaskVisible, clearedTask,
- targetTask.getTopNonFinishingActivity().isVisible());
+ targetTask.getTaskInfo(), homeTaskVisible, clearedTask, visible);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0da47ca..faf3f06 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12474,6 +12474,22 @@
}
@Override
+ public boolean isActiveDeviceOwner(int uid) {
+ synchronized (getLockObject()) {
+ return getActiveAdminWithPolicyForUidLocked(
+ null, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, uid) != null;
+ }
+ }
+
+ @Override
+ public boolean isActiveProfileOwner(int uid) {
+ synchronized (getLockObject()) {
+ return getActiveAdminWithPolicyForUidLocked(
+ null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, uid) != null;
+ }
+ }
+
+ @Override
public boolean isActiveSupervisionApp(int uid) {
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index c7b45ef..6ab0697 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1100,6 +1100,34 @@
}
/**
+ * Verify the visibility of a show-when-locked and dismiss keyguard activity on sleeping
+ * display.
+ */
+ @Test
+ public void testDisplaySleeping_activityInvisible() {
+ final KeyguardController keyguardController =
+ mActivity.mStackSupervisor.getKeyguardController();
+ doReturn(true).when(keyguardController).isKeyguardLocked();
+ final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ topActivity.mVisibleRequested = true;
+ topActivity.nowVisible = true;
+ topActivity.setState(RESUMED, "test" /*reason*/);
+ doReturn(true).when(topActivity).containsDismissKeyguardWindow();
+ doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
+ any() /* starting */, anyInt() /* configChanges */,
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+ topActivity.setShowWhenLocked(true);
+
+ // Verify the top activity is occluded keyguard.
+ assertEquals(topActivity, mStack.topRunningActivity());
+ assertTrue(mStack.topActivityOccludesKeyguard());
+
+ final DisplayContent display = mActivity.mDisplayContent;
+ doReturn(true).when(display).isSleeping();
+ assertFalse(topActivity.shouldBeVisible());
+ }
+
+ /**
* Verify that complete finish request for a show-when-locked activity must ensure the
* keyguard occluded state being updated.
*/
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a85eb53..1238e7b 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1468,8 +1468,11 @@
/**
* Writes the string {@param input} into the outgoing text stream for this RTT call. Since
- * RTT transmits text in real-time, this method should be called once for each character
- * the user enters into the device.
+ * RTT transmits text in real-time, this method should be called once for each user action.
+ * For example, when the user enters text as discrete characters using the keyboard, this
+ * method should be called once for each character. However, if the user enters text by
+ * pasting or autocomplete, the entire contents of the pasted or autocompleted text should
+ * be sent in one call to this method.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2e51ef1..3aa9345 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1365,6 +1365,7 @@
* include those that were inserted before, maybe empty but not null.
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
public List<SubscriptionInfo> getAllSubscriptionInfoList() {
if (VDBG) logd("[getAllSubscriptionInfoList]+");
@@ -1382,7 +1383,7 @@
}
if (result == null) {
- result = new ArrayList<>();
+ result = Collections.emptyList();
}
return result;
}
diff --git a/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl b/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl
new file mode 100644
index 0000000..bbab548
--- /dev/null
+++ b/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.telephony.ims;
+
+parcelable AudioCodecAttributes;
diff --git a/telephony/java/android/telephony/ims/AudioCodecAttributes.java b/telephony/java/android/telephony/ims/AudioCodecAttributes.java
new file mode 100644
index 0000000..7b6ab00
--- /dev/null
+++ b/telephony/java/android/telephony/ims/AudioCodecAttributes.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Range;
+
+/**
+ * Parcelable object to handle audio codec attributes.
+ * It provides the audio codec bitrate, bandwidth and their upper/lower bound.
+ *
+ * @hide
+ */
+@SystemApi
+public final class AudioCodecAttributes implements Parcelable {
+ // The audio codec bitrate in kbps.
+ private float mBitrateKbps;
+ // The range of the audio codec bitrate in kbps.
+ private Range<Float> mBitrateRangeKbps;
+ // The audio codec bandwidth in kHz.
+ private float mBandwidthKhz;
+ // The range of the audio codec bandwidth in kHz.
+ private Range<Float> mBandwidthRangeKhz;
+
+
+ /**
+ * Constructor.
+ *
+ * @param bitrateKbps The audio codec bitrate in kbps.
+ * @param bitrateRangeKbps The range of the audio codec bitrate in kbps.
+ * @param bandwidthKhz The audio codec bandwidth in kHz.
+ * @param bandwidthRangeKhz The range of the audio codec bandwidth in kHz.
+ */
+
+ public AudioCodecAttributes(float bitrateKbps, @NonNull Range<Float> bitrateRangeKbps,
+ float bandwidthKhz, @NonNull Range<Float> bandwidthRangeKhz) {
+ mBitrateKbps = bitrateKbps;
+ mBitrateRangeKbps = bitrateRangeKbps;
+ mBandwidthKhz = bandwidthKhz;
+ mBandwidthRangeKhz = bandwidthRangeKhz;
+ }
+
+ private AudioCodecAttributes(Parcel in) {
+ mBitrateKbps = in.readFloat();
+ mBitrateRangeKbps = new Range<>(in.readFloat(), in.readFloat());
+ mBandwidthKhz = in.readFloat();
+ mBandwidthRangeKhz = new Range<>(in.readFloat(), in.readFloat());
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeFloat(mBitrateKbps);
+ out.writeFloat(mBitrateRangeKbps.getLower());
+ out.writeFloat(mBitrateRangeKbps.getUpper());
+ out.writeFloat(mBandwidthKhz);
+ out.writeFloat(mBandwidthRangeKhz.getLower());
+ out.writeFloat(mBandwidthRangeKhz.getUpper());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<AudioCodecAttributes> CREATOR =
+ new Creator<AudioCodecAttributes>() {
+ @Override
+ public AudioCodecAttributes createFromParcel(Parcel in) {
+ return new AudioCodecAttributes(in);
+ }
+
+ @Override
+ public AudioCodecAttributes[] newArray(int size) {
+ return new AudioCodecAttributes[size];
+ }
+ };
+
+ /**
+ * @return the exact value of the audio codec bitrate in kbps.
+ */
+ public float getBitrateKbps() {
+ return mBitrateKbps;
+ }
+
+ /**
+ * @return the range of the audio codec bitrate in kbps
+ */
+ public @NonNull Range<Float> getBitrateRangeKbps() {
+ return mBitrateRangeKbps;
+ }
+
+ /**
+ * @return the exact value of the audio codec bandwidth in kHz.
+ */
+ public float getBandwidthKhz() {
+ return mBandwidthKhz;
+ }
+
+ /**
+ * @return the range of the audio codec bandwidth in kHz.
+ */
+ public @NonNull Range<Float> getBandwidthRangeKhz() {
+ return mBandwidthRangeKhz;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "{ bitrateKbps=" + mBitrateKbps
+ + ", bitrateRangeKbps=" + mBitrateRangeKbps
+ + ", bandwidthKhz=" + mBandwidthKhz
+ + ", bandwidthRangeKhz=" + mBandwidthRangeKhz + " }";
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 131cb1a..4aca48b 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
@@ -89,6 +90,9 @@
/** @hide */
@UnsupportedAppUsage
public int mAudioDirection;
+ // Audio codec attributes
+ private AudioCodecAttributes mAudioCodecAttributes;
+
// Video related information
/** @hide */
public int mVideoQuality;
@@ -190,6 +194,7 @@
public void copyFrom(ImsStreamMediaProfile profile) {
mAudioQuality = profile.mAudioQuality;
mAudioDirection = profile.mAudioDirection;
+ mAudioCodecAttributes = profile.mAudioCodecAttributes;
mVideoQuality = profile.mVideoQuality;
mVideoDirection = profile.mVideoDirection;
mRttMode = profile.mRttMode;
@@ -198,12 +203,13 @@
@NonNull
@Override
public String toString() {
- return "{ audioQuality=" + mAudioQuality +
- ", audioDirection=" + mAudioDirection +
- ", videoQuality=" + mVideoQuality +
- ", videoDirection=" + mVideoDirection +
- ", rttMode=" + mRttMode +
- ", hasRttAudioSpeech=" + mIsReceivingRttAudio + " }";
+ return "{ audioQuality=" + mAudioQuality
+ + ", audioDirection=" + mAudioDirection
+ + ", audioCodecAttribute=" + mAudioCodecAttributes
+ + ", videoQuality=" + mVideoQuality
+ + ", videoDirection=" + mVideoDirection
+ + ", rttMode=" + mRttMode
+ + ", hasRttAudioSpeech=" + mIsReceivingRttAudio + " }";
}
@Override
@@ -215,6 +221,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mAudioQuality);
out.writeInt(mAudioDirection);
+ out.writeTypedObject(mAudioCodecAttributes, flags);
out.writeInt(mVideoQuality);
out.writeInt(mVideoDirection);
out.writeInt(mRttMode);
@@ -224,6 +231,7 @@
private void readFromParcel(Parcel in) {
mAudioQuality = in.readInt();
mAudioDirection = in.readInt();
+ mAudioCodecAttributes = in.readTypedObject(AudioCodecAttributes.CREATOR);
mVideoQuality = in.readInt();
mVideoDirection = in.readInt();
mRttMode = in.readInt();
@@ -274,6 +282,23 @@
return mAudioDirection;
}
+ /**
+ * Get the audio codec attributes {@link AudioCodecAttributes} which may be {@code null} if
+ * ImsService doesn't support this information.
+ * @return audio codec attributes
+ */
+ public @Nullable AudioCodecAttributes getAudioCodecAttributes() {
+ return mAudioCodecAttributes;
+ }
+
+ /**
+ * Set the audio codec attributes {@link AudioCodecAttributes} which includes bitrate and
+ * bandwidth information.
+ */
+ public void setAudioCodecAttributes(@NonNull AudioCodecAttributes audioCodecAttributes) {
+ mAudioCodecAttributes = audioCodecAttributes;
+ }
+
public int getVideoQuality() {
return mVideoQuality;
}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 11a83eb..6b7ea66 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -359,7 +359,7 @@
assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
public void testOemPrivate() {
NetworkCapabilities nc = new NetworkCapabilities();
// By default OEM_PRIVATE is neither in the unwanted or required lists and the network is
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index de1028c..c53462c 100644
--- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -34,6 +34,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -53,6 +54,7 @@
import android.net.StringNetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.os.Handler;
+import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
@@ -91,6 +93,7 @@
private static final int POLICY_SNOOZED = -100;
@Mock private Context mContext;
+ @Mock private Context mUserAllContext;
@Mock private Resources mResources;
@Mock private Handler mHandler;
@Mock private MultipathPolicyTracker.Dependencies mDeps;
@@ -127,8 +130,11 @@
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
- when(mContext.registerReceiverAsUser(mConfigChangeReceiverCaptor.capture(),
- any(), argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
+ doReturn(UserHandle.ALL.getIdentifier()).when(mUserAllContext).getUserId();
+ when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt()))
+ .thenReturn(mUserAllContext);
+ when(mUserAllContext.registerReceiver(mConfigChangeReceiverCaptor.capture(),
+ argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
.thenReturn(null);
when(mDeps.getClock()).thenReturn(mClock);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 2fa0914..a553b58 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -241,7 +241,7 @@
doNothing().when(mNetService).registerObserver(any());
// Deny all appops by default.
- when(mAppOps.noteOpNoThrow(anyInt(), anyInt(), anyString()))
+ when(mAppOps.noteOpNoThrow(anyString(), anyInt(), anyString(), any(), any()))
.thenReturn(AppOpsManager.MODE_IGNORED);
// Setup IpSecService
@@ -729,26 +729,27 @@
assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
}
- private Vpn createVpnAndSetupUidChecks(int... grantedOps) throws Exception {
+ private Vpn createVpnAndSetupUidChecks(String... grantedOps) throws Exception {
return createVpnAndSetupUidChecks(primaryUser, grantedOps);
}
- private Vpn createVpnAndSetupUidChecks(UserInfo user, int... grantedOps) throws Exception {
+ private Vpn createVpnAndSetupUidChecks(UserInfo user, String... grantedOps) throws Exception {
final Vpn vpn = createVpn(user.id);
setMockedUsers(user);
when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
.thenReturn(Process.myUid());
- for (final int op : grantedOps) {
- when(mAppOps.noteOpNoThrow(op, Process.myUid(), TEST_VPN_PKG))
+ for (final String opStr : grantedOps) {
+ when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG,
+ null /* attributionTag */, null /* message */))
.thenReturn(AppOpsManager.MODE_ALLOWED);
}
return vpn;
}
- private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, int... checkedOps) {
+ private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore));
// The profile should always be stored, whether or not consent has been previously granted.
@@ -759,8 +760,9 @@
eq(Process.SYSTEM_UID),
eq(0));
- for (final int checkedOp : checkedOps) {
- verify(mAppOps).noteOpNoThrow(checkedOp, Process.myUid(), TEST_VPN_PKG);
+ for (final String checkedOpStr : checkedOps) {
+ verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
+ null /* attributionTag */, null /* message */);
}
}
@@ -768,11 +770,11 @@
public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
.thenReturn(false);
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
fail("Expected exception due to missing feature");
} catch (UnsupportedOperationException expected) {
}
@@ -780,10 +782,10 @@
@Test
public void testProvisionVpnProfilePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
}
@Test
@@ -793,19 +795,19 @@
// Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
// had neither.
checkProvisionVpnProfile(vpn, false /* expectedResult */,
- AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, AppOpsManager.OP_ACTIVATE_VPN);
+ AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
@Test
public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
- checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_VPN);
+ checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
@Test
public void testProvisionVpnProfileTooLarge() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
final VpnProfile bigProfile = new VpnProfile("");
bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
@@ -821,7 +823,7 @@
public void testProvisionVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore);
@@ -844,7 +846,7 @@
public void testDeleteVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
@@ -867,7 +869,7 @@
@Test
public void testStartVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -877,14 +879,16 @@
verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
}
@Test
public void testStartVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -892,7 +896,8 @@
vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
// Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown.
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG);
+ verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
+ TEST_VPN_PKG, null /* attributionTag */, null /* message */);
}
@Test
@@ -908,10 +913,13 @@
// Verify both appops were checked.
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG);
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
+ verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
+ TEST_VPN_PKG, null /* attributionTag */, null /* message */);
// Keystore should never have been accessed.
verify(mKeyStore, never()).get(any());
@@ -919,7 +927,7 @@
@Test
public void testStartVpnProfileMissingProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
@@ -932,16 +940,18 @@
verify(mKeyStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
}
@Test
public void testStartVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
@@ -954,7 +964,7 @@
public void testStopVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.stopVpnProfile(TEST_VPN_PKG);
@@ -970,7 +980,7 @@
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
@@ -983,7 +993,7 @@
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_PLATFORM));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
@@ -996,13 +1006,13 @@
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_IGNORED));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_IGNORED));
@@ -1059,7 +1069,7 @@
verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
verify(mAppOps).setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
verify(mSystemServices).settingsSecurePutStringForUser(
diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
index 858358c..8b730af 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
@@ -22,7 +22,6 @@
import android.Manifest;
import android.Manifest.permission;
import android.app.AppOpsManager;
-import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -167,13 +166,11 @@
}
private void setIsDeviceOwner(boolean isOwner) {
- when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER))
- .thenReturn(isOwner);
+ when(mDpmi.isActiveDeviceOwner(TEST_UID)).thenReturn(isOwner);
}
private void setIsProfileOwner(boolean isOwner) {
- when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER))
- .thenReturn(isOwner);
+ when(mDpmi.isActiveProfileOwner(TEST_UID)).thenReturn(isOwner);
}
private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
new file mode 100644
index 0000000..f967bf0
--- /dev/null
+++ b/tests/vcn/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// Build FrameworksVcnTests package
+//########################################################################
+
+android_test {
+ name: "FrameworksVcnTests",
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.kt",
+ ],
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ "framework-protos",
+ "mockito-target-minus-junit4",
+ "platform-test-annotations",
+ "services.core",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+}
diff --git a/tests/vcn/AndroidManifest.xml b/tests/vcn/AndroidManifest.xml
new file mode 100644
index 0000000..2ad9aac
--- /dev/null
+++ b/tests/vcn/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.tests.vcn">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.tests.vcn"
+ android:label="Frameworks VCN Tests" />
+</manifest>
diff --git a/tests/vcn/AndroidTest.xml b/tests/vcn/AndroidTest.xml
new file mode 100644
index 0000000..dc521fd
--- /dev/null
+++ b/tests/vcn/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs VCN Tests.">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="FrameworksVcnTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-tag" value="FrameworksVcnTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.tests.vcn" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/tests/vcn/TEST_MAPPING b/tests/vcn/TEST_MAPPING
new file mode 100644
index 0000000..54fa411
--- /dev/null
+++ b/tests/vcn/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksVcnTests"
+ }
+ ]
+}
\ No newline at end of file