Merge "Remove suspected false positives from light greylist."
diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS
index d6bb71b..85adfa7 100644
--- a/core/java/android/annotation/OWNERS
+++ b/core/java/android/annotation/OWNERS
@@ -1 +1,2 @@
 tnorbye@google.com
+per-file UnsupportedAppUsage.java = mathewi@google.com
diff --git a/core/java/android/annotation/UnsupportedAppUsage.java b/core/java/android/annotation/UnsupportedAppUsage.java
index fbba6da..28145a0 100644
--- a/core/java/android/annotation/UnsupportedAppUsage.java
+++ b/core/java/android/annotation/UnsupportedAppUsage.java
@@ -27,15 +27,15 @@
  * Indicates that a class member, that is not part of the SDK, is used by apps.
  * Since the member is not part of the SDK, such use is not supported.
  *
- * This annotation acts as a heads up that changing a given method or field
+ * <p>This annotation acts as a heads up that changing a given method or field
  * may affect apps, potentially breaking them when the next Android version is
  * released. In some cases, for members that are heavily used, this annotation
  * may imply restrictions on changes to the member.
  *
- * This annotation also results in access to the member being permitted by the
+ * <p>This annotation also results in access to the member being permitted by the
  * runtime, with a warning being generated in debug builds.
  *
- * For more details, see go/UnsupportedAppUsage.
+ * <p>For more details, see go/UnsupportedAppUsage.
  *
  * {@hide}
  */
@@ -53,15 +53,15 @@
     /**
      * Indicates that usage of this API is limited to apps based on their target SDK version.
      *
-     * Access to the API is allowed if the targetSdkVersion in the apps manifest is no greater than
-     * this value. Access checks are performed at runtime.
+     * <p>Access to the API is allowed if the targetSdkVersion in the apps manifest is no greater
+     * than this value. Access checks are performed at runtime.
      *
-     * This is used to give app developers a grace period to migrate off a non-SDK interface. When
-     * making Android version N, existing APIs can have a maxTargetSdk of N-1 added to them.
+     * <p>This is used to give app developers a grace period to migrate off a non-SDK interface.
+     * When making Android version N, existing APIs can have a maxTargetSdk of N-1 added to them.
      * Developers must then migrate off the API when their app is updated in future, but it will
      * continue working in the meantime.
      *
-     * Possible values are:
+     * <p>Possible values are:
      * <ul>
      *     <li>
      *         {@link android.os.Build.VERSION_CODES#O} or {@link android.os.Build.VERSION_CODES#P},
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index d25e59f..9a4ea9e7 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -28,6 +28,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Represents a distinct method to place or receive a phone call. Apps which can place calls and
@@ -360,6 +361,33 @@
     private boolean mIsEnabled;
     private String mGroupId;
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PhoneAccount that = (PhoneAccount) o;
+        return mCapabilities == that.mCapabilities &&
+                mHighlightColor == that.mHighlightColor &&
+                mSupportedAudioRoutes == that.mSupportedAudioRoutes &&
+                mIsEnabled == that.mIsEnabled &&
+                Objects.equals(mAccountHandle, that.mAccountHandle) &&
+                Objects.equals(mAddress, that.mAddress) &&
+                Objects.equals(mSubscriptionAddress, that.mSubscriptionAddress) &&
+                Objects.equals(mLabel, that.mLabel) &&
+                Objects.equals(mShortDescription, that.mShortDescription) &&
+                Objects.equals(mSupportedUriSchemes, that.mSupportedUriSchemes) &&
+                areBundlesEqual(mExtras, that.mExtras) &&
+                Objects.equals(mGroupId, that.mGroupId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mAccountHandle, mAddress, mSubscriptionAddress, mCapabilities,
+                mHighlightColor, mLabel, mShortDescription, mSupportedUriSchemes,
+                mSupportedAudioRoutes,
+                mExtras, mIsEnabled, mGroupId);
+    }
+
     /**
      * Helper class for creating a {@link PhoneAccount}.
      */
@@ -1022,4 +1050,31 @@
 
         return sb.toString();
     }
+
+    /**
+     * Determines if two {@link Bundle}s are equal.
+     * @param extras First {@link Bundle} to check.
+     * @param newExtras {@link Bundle} to compare against.
+     * @return {@code true} if the {@link Bundle}s are equal, {@code false} otherwise.
+     */
+    private static boolean areBundlesEqual(Bundle extras, Bundle newExtras) {
+        if (extras == null || newExtras == null) {
+            return extras == newExtras;
+        }
+
+        if (extras.size() != newExtras.size()) {
+            return false;
+        }
+
+        for(String key : extras.keySet()) {
+            if (key != null) {
+                final Object value = extras.get(key);
+                final Object newValue = newExtras.get(key);
+                if (!Objects.equals(value, newValue)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
 }