Loading core/api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -9834,6 +9834,7 @@ package android.companion { public final class AssociationInfo implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.companion.AssociatedDevice getAssociatedDevice(); method @FlaggedApi("android.companion.association_device_icon") @Nullable public android.graphics.drawable.Icon getDeviceIcon(); method @Nullable public android.net.MacAddress getDeviceMacAddress(); method @Nullable public String getDeviceProfile(); method @Nullable public CharSequence getDisplayName(); Loading @@ -9847,6 +9848,7 @@ package android.companion { public final class AssociationRequest implements android.os.Parcelable { method public int describeContents(); method @FlaggedApi("android.companion.association_device_icon") @Nullable public android.graphics.drawable.Icon getDeviceIcon(); method @Nullable public String getDeviceProfile(); method @Nullable public CharSequence getDisplayName(); method public boolean isForceConfirmation(); Loading @@ -9866,6 +9868,7 @@ package android.companion { ctor public AssociationRequest.Builder(); method @NonNull public android.companion.AssociationRequest.Builder addDeviceFilter(@Nullable android.companion.DeviceFilter<?>); method @NonNull public android.companion.AssociationRequest build(); method @FlaggedApi("android.companion.association_device_icon") @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setDeviceIcon(@NonNull android.graphics.drawable.Icon); method @NonNull public android.companion.AssociationRequest.Builder setDeviceProfile(@NonNull String); method @NonNull public android.companion.AssociationRequest.Builder setDisplayName(@NonNull CharSequence); method @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setForceConfirmation(boolean); core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -914,6 +914,7 @@ package android.companion { ctor public AssociationInfo.Builder(@NonNull android.companion.AssociationInfo); method @NonNull public android.companion.AssociationInfo build(); method @NonNull public android.companion.AssociationInfo.Builder setAssociatedDevice(@Nullable android.companion.AssociatedDevice); method @FlaggedApi("android.companion.association_device_icon") @NonNull public android.companion.AssociationInfo.Builder setDeviceIcon(@Nullable android.graphics.drawable.Icon); method @NonNull public android.companion.AssociationInfo.Builder setDeviceMacAddress(@Nullable android.net.MacAddress); method @NonNull public android.companion.AssociationInfo.Builder setDeviceProfile(@Nullable String); method @NonNull public android.companion.AssociationInfo.Builder setDisplayName(@Nullable CharSequence); Loading core/java/android/companion/AssociationInfo.java +52 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UserIdInt; import android.graphics.drawable.Icon; import android.net.MacAddress; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -85,6 +86,11 @@ public final class AssociationInfo implements Parcelable { private final long mLastTimeConnectedMs; private final int mSystemDataSyncFlags; /** * A device icon displayed on a selfManaged association dialog. */ private final Icon mDeviceIcon; /** * Creates a new Association. * Loading @@ -95,7 +101,7 @@ public final class AssociationInfo implements Parcelable { @Nullable CharSequence displayName, @Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice, boolean selfManaged, boolean notifyOnDeviceNearby, boolean revoked, boolean pending, long timeApprovedMs, long lastTimeConnectedMs, int systemDataSyncFlags) { long lastTimeConnectedMs, int systemDataSyncFlags, @Nullable Icon deviceIcon) { if (id <= 0) { throw new IllegalArgumentException("Association ID should be greater than 0"); } Loading @@ -119,6 +125,7 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = timeApprovedMs; mLastTimeConnectedMs = lastTimeConnectedMs; mSystemDataSyncFlags = systemDataSyncFlags; mDeviceIcon = deviceIcon; } /** Loading Loading @@ -277,6 +284,20 @@ public final class AssociationInfo implements Parcelable { return mSystemDataSyncFlags; } /** * Get the device icon of the associated device. The device icon represents the device type. * * @return the device icon, or {@code null} if no device icon is has been set for the * associated device. * * @see AssociationRequest.Builder#setDeviceIcon(Icon) */ @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON) @Nullable public Icon getDeviceIcon() { return mDeviceIcon; } /** * Utility method for checking if the association represents a device with the given MAC * address. Loading Loading @@ -370,14 +391,16 @@ public final class AssociationInfo implements Parcelable { && Objects.equals(mDisplayName, that.mDisplayName) && Objects.equals(mDeviceProfile, that.mDeviceProfile) && Objects.equals(mAssociatedDevice, that.mAssociatedDevice) && mSystemDataSyncFlags == that.mSystemDataSyncFlags; && mSystemDataSyncFlags == that.mSystemDataSyncFlags && (mDeviceIcon == null ? that.mDeviceIcon == null : mDeviceIcon.sameAs(that.mDeviceIcon)); } @Override public int hashCode() { return Objects.hash(mId, mUserId, mPackageName, mTag, mDeviceMacAddress, mDisplayName, mDeviceProfile, mAssociatedDevice, mSelfManaged, mNotifyOnDeviceNearby, mRevoked, mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags); mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags, mDeviceIcon); } @Override Loading @@ -402,6 +425,12 @@ public final class AssociationInfo implements Parcelable { dest.writeLong(mTimeApprovedMs); dest.writeLong(mLastTimeConnectedMs); dest.writeInt(mSystemDataSyncFlags); if (mDeviceIcon != null) { dest.writeInt(1); mDeviceIcon.writeToParcel(dest, flags); } else { dest.writeInt(0); } } private AssociationInfo(@NonNull Parcel in) { Loading @@ -420,6 +449,11 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = in.readLong(); mLastTimeConnectedMs = in.readLong(); mSystemDataSyncFlags = in.readInt(); if (in.readInt() == 1) { mDeviceIcon = Icon.CREATOR.createFromParcel(in); } else { mDeviceIcon = null; } } @NonNull Loading Loading @@ -459,6 +493,7 @@ public final class AssociationInfo implements Parcelable { private long mTimeApprovedMs; private long mLastTimeConnectedMs; private int mSystemDataSyncFlags; private Icon mDeviceIcon; /** @hide */ @TestApi Loading Loading @@ -486,6 +521,7 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = info.mTimeApprovedMs; mLastTimeConnectedMs = info.mLastTimeConnectedMs; mSystemDataSyncFlags = info.mSystemDataSyncFlags; mDeviceIcon = info.mDeviceIcon; } /** Loading @@ -510,6 +546,7 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = info.mTimeApprovedMs; mLastTimeConnectedMs = info.mLastTimeConnectedMs; mSystemDataSyncFlags = info.mSystemDataSyncFlags; mDeviceIcon = info.mDeviceIcon; } /** @hide */ Loading Loading @@ -622,6 +659,16 @@ public final class AssociationInfo implements Parcelable { return this; } /** @hide */ @TestApi @NonNull @SuppressLint("MissingGetterMatchingBuilder") @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON) public Builder setDeviceIcon(@Nullable Icon deviceIcon) { mDeviceIcon = deviceIcon; return this; } /** @hide */ @TestApi @NonNull Loading @@ -648,7 +695,8 @@ public final class AssociationInfo implements Parcelable { mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags mSystemDataSyncFlags, mDeviceIcon ); } } Loading core/java/android/companion/AssociationRequest.java +60 −4 Original line number Diff line number Diff line Loading @@ -23,12 +23,14 @@ import static com.android.internal.util.CollectionUtils.emptyIfNull; import static java.util.Objects.requireNonNull; import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.StringDef; import android.annotation.UserIdInt; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.drawable.Icon; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -233,6 +235,13 @@ public final class AssociationRequest implements Parcelable { */ private boolean mSkipPrompt; /** * The device icon displayed in selfManaged association dialog. * @hide */ @Nullable private Icon mDeviceIcon; /** * Creates a new AssociationRequest. * Loading @@ -258,15 +267,16 @@ public final class AssociationRequest implements Parcelable { @Nullable @DeviceProfile String deviceProfile, @Nullable CharSequence displayName, boolean selfManaged, boolean forceConfirmation) { boolean forceConfirmation, @Nullable Icon deviceIcon) { mSingleDevice = singleDevice; mDeviceFilters = requireNonNull(deviceFilters); mDeviceProfile = deviceProfile; mDisplayName = displayName; mSelfManaged = selfManaged; mForceConfirmation = forceConfirmation; mCreationTime = System.currentTimeMillis(); mDeviceIcon = deviceIcon; } /** Loading Loading @@ -318,6 +328,19 @@ public final class AssociationRequest implements Parcelable { return mSingleDevice; } /** * Get the device icon of the self-managed association request. * * @return the device icon, or {@code null} if no device icon has been set. * * @see Builder#setDeviceIcon(Icon) */ @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON) @Nullable public Icon getDeviceIcon() { return mDeviceIcon; } /** @hide */ public void setPackageName(@NonNull String packageName) { mPackageName = packageName; Loading Loading @@ -365,6 +388,7 @@ public final class AssociationRequest implements Parcelable { private CharSequence mDisplayName; private boolean mSelfManaged = false; private boolean mForceConfirmation = false; private Icon mDeviceIcon = null; public Builder() {} Loading Loading @@ -450,6 +474,23 @@ public final class AssociationRequest implements Parcelable { return this; } /** * Set the device icon for the self-managed device and this icon will be * displayed in the self-managed association dialog. * * @throws IllegalArgumentException if the icon is not exactly 24dp by 24dp * or if it is {@link Icon#TYPE_URI} or {@link Icon#TYPE_URI_ADAPTIVE_BITMAP}. * @see #setSelfManaged(boolean) */ @NonNull @RequiresPermission(REQUEST_COMPANION_SELF_MANAGED) @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON) public Builder setDeviceIcon(@NonNull Icon deviceIcon) { checkNotUsed(); mDeviceIcon = requireNonNull(deviceIcon); return this; } /** @inheritDoc */ @NonNull @Override Loading @@ -460,7 +501,7 @@ public final class AssociationRequest implements Parcelable { + "provide the display name of the device"); } return new AssociationRequest(mSingleDevice, emptyIfNull(mDeviceFilters), mDeviceProfile, mDisplayName, mSelfManaged, mForceConfirmation); mDeviceProfile, mDisplayName, mSelfManaged, mForceConfirmation, mDeviceIcon); } } Loading Loading @@ -561,7 +602,9 @@ public final class AssociationRequest implements Parcelable { && Objects.equals(mDeviceProfilePrivilegesDescription, that.mDeviceProfilePrivilegesDescription) && mCreationTime == that.mCreationTime && mSkipPrompt == that.mSkipPrompt; && mSkipPrompt == that.mSkipPrompt && (mDeviceIcon == null ? that.mDeviceIcon == null : mDeviceIcon.sameAs(that.mDeviceIcon)); } @Override Loading @@ -579,6 +622,8 @@ public final class AssociationRequest implements Parcelable { _hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription); _hash = 31 * _hash + Long.hashCode(mCreationTime); _hash = 31 * _hash + Boolean.hashCode(mSkipPrompt); _hash = 31 * _hash + Objects.hashCode(mDeviceIcon); return _hash; } Loading Loading @@ -606,6 +651,12 @@ public final class AssociationRequest implements Parcelable { dest.writeString8(mDeviceProfilePrivilegesDescription); } dest.writeLong(mCreationTime); if (mDeviceIcon != null) { dest.writeInt(1); mDeviceIcon.writeToParcel(dest, flags); } else { dest.writeInt(0); } } @Override Loading Loading @@ -650,6 +701,11 @@ public final class AssociationRequest implements Parcelable { this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription; this.mCreationTime = creationTime; this.mSkipPrompt = skipPrompt; if (in.readInt() == 1) { mDeviceIcon = Icon.CREATOR.createFromParcel(in); } else { mDeviceIcon = null; } } @NonNull Loading core/java/android/companion/CompanionDeviceManager.java +44 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMIN import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION; import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER; import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH; import static android.graphics.drawable.Icon.TYPE_URI; import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP; import android.annotation.CallbackExecutor; Loading Loading @@ -49,6 +51,11 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.VectorDrawable; import android.net.MacAddress; import android.os.Binder; import android.os.Handler; Loading Loading @@ -535,6 +542,13 @@ public final class CompanionDeviceManager { Objects.requireNonNull(executor, "Executor cannot be null"); Objects.requireNonNull(callback, "Callback cannot be null"); final Icon deviceIcon = request.getDeviceIcon(); if (deviceIcon != null && !isValidIcon(deviceIcon, mContext)) { throw new IllegalArgumentException("The size of the device icon must be 24dp x 24dp to" + "ensure proper display"); } try { mService.associate(request, new AssociationRequestCallbackProxy(executor, callback), mContext.getOpPackageName(), mContext.getUserId()); Loading Loading @@ -2027,4 +2041,34 @@ public final class CompanionDeviceManager { } } } private boolean isValidIcon(Icon icon, Context context) { if (icon.getType() == TYPE_URI_ADAPTIVE_BITMAP || icon.getType() == TYPE_URI) { throw new IllegalArgumentException("The URI based Icon is not supported."); } Drawable drawable = icon.loadDrawable(context); float density = context.getResources().getDisplayMetrics().density; if (drawable instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); float widthDp = bitmap.getWidth() / density; float heightDp = bitmap.getHeight() / density; if (widthDp != 24 || heightDp != 24) { return false; } } else if (drawable instanceof VectorDrawable) { VectorDrawable vectorDrawable = (VectorDrawable) drawable; float widthDp = vectorDrawable.getIntrinsicWidth() / density; float heightDp = vectorDrawable.getIntrinsicHeight() / density; if (widthDp != 24 || heightDp != 24) { return false; } } else { throw new IllegalArgumentException("The format of the device icon is unsupported."); } return true; } } Loading
core/api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -9834,6 +9834,7 @@ package android.companion { public final class AssociationInfo implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.companion.AssociatedDevice getAssociatedDevice(); method @FlaggedApi("android.companion.association_device_icon") @Nullable public android.graphics.drawable.Icon getDeviceIcon(); method @Nullable public android.net.MacAddress getDeviceMacAddress(); method @Nullable public String getDeviceProfile(); method @Nullable public CharSequence getDisplayName(); Loading @@ -9847,6 +9848,7 @@ package android.companion { public final class AssociationRequest implements android.os.Parcelable { method public int describeContents(); method @FlaggedApi("android.companion.association_device_icon") @Nullable public android.graphics.drawable.Icon getDeviceIcon(); method @Nullable public String getDeviceProfile(); method @Nullable public CharSequence getDisplayName(); method public boolean isForceConfirmation(); Loading @@ -9866,6 +9868,7 @@ package android.companion { ctor public AssociationRequest.Builder(); method @NonNull public android.companion.AssociationRequest.Builder addDeviceFilter(@Nullable android.companion.DeviceFilter<?>); method @NonNull public android.companion.AssociationRequest build(); method @FlaggedApi("android.companion.association_device_icon") @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setDeviceIcon(@NonNull android.graphics.drawable.Icon); method @NonNull public android.companion.AssociationRequest.Builder setDeviceProfile(@NonNull String); method @NonNull public android.companion.AssociationRequest.Builder setDisplayName(@NonNull CharSequence); method @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setForceConfirmation(boolean);
core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -914,6 +914,7 @@ package android.companion { ctor public AssociationInfo.Builder(@NonNull android.companion.AssociationInfo); method @NonNull public android.companion.AssociationInfo build(); method @NonNull public android.companion.AssociationInfo.Builder setAssociatedDevice(@Nullable android.companion.AssociatedDevice); method @FlaggedApi("android.companion.association_device_icon") @NonNull public android.companion.AssociationInfo.Builder setDeviceIcon(@Nullable android.graphics.drawable.Icon); method @NonNull public android.companion.AssociationInfo.Builder setDeviceMacAddress(@Nullable android.net.MacAddress); method @NonNull public android.companion.AssociationInfo.Builder setDeviceProfile(@Nullable String); method @NonNull public android.companion.AssociationInfo.Builder setDisplayName(@Nullable CharSequence); Loading
core/java/android/companion/AssociationInfo.java +52 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UserIdInt; import android.graphics.drawable.Icon; import android.net.MacAddress; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -85,6 +86,11 @@ public final class AssociationInfo implements Parcelable { private final long mLastTimeConnectedMs; private final int mSystemDataSyncFlags; /** * A device icon displayed on a selfManaged association dialog. */ private final Icon mDeviceIcon; /** * Creates a new Association. * Loading @@ -95,7 +101,7 @@ public final class AssociationInfo implements Parcelable { @Nullable CharSequence displayName, @Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice, boolean selfManaged, boolean notifyOnDeviceNearby, boolean revoked, boolean pending, long timeApprovedMs, long lastTimeConnectedMs, int systemDataSyncFlags) { long lastTimeConnectedMs, int systemDataSyncFlags, @Nullable Icon deviceIcon) { if (id <= 0) { throw new IllegalArgumentException("Association ID should be greater than 0"); } Loading @@ -119,6 +125,7 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = timeApprovedMs; mLastTimeConnectedMs = lastTimeConnectedMs; mSystemDataSyncFlags = systemDataSyncFlags; mDeviceIcon = deviceIcon; } /** Loading Loading @@ -277,6 +284,20 @@ public final class AssociationInfo implements Parcelable { return mSystemDataSyncFlags; } /** * Get the device icon of the associated device. The device icon represents the device type. * * @return the device icon, or {@code null} if no device icon is has been set for the * associated device. * * @see AssociationRequest.Builder#setDeviceIcon(Icon) */ @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON) @Nullable public Icon getDeviceIcon() { return mDeviceIcon; } /** * Utility method for checking if the association represents a device with the given MAC * address. Loading Loading @@ -370,14 +391,16 @@ public final class AssociationInfo implements Parcelable { && Objects.equals(mDisplayName, that.mDisplayName) && Objects.equals(mDeviceProfile, that.mDeviceProfile) && Objects.equals(mAssociatedDevice, that.mAssociatedDevice) && mSystemDataSyncFlags == that.mSystemDataSyncFlags; && mSystemDataSyncFlags == that.mSystemDataSyncFlags && (mDeviceIcon == null ? that.mDeviceIcon == null : mDeviceIcon.sameAs(that.mDeviceIcon)); } @Override public int hashCode() { return Objects.hash(mId, mUserId, mPackageName, mTag, mDeviceMacAddress, mDisplayName, mDeviceProfile, mAssociatedDevice, mSelfManaged, mNotifyOnDeviceNearby, mRevoked, mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags); mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags, mDeviceIcon); } @Override Loading @@ -402,6 +425,12 @@ public final class AssociationInfo implements Parcelable { dest.writeLong(mTimeApprovedMs); dest.writeLong(mLastTimeConnectedMs); dest.writeInt(mSystemDataSyncFlags); if (mDeviceIcon != null) { dest.writeInt(1); mDeviceIcon.writeToParcel(dest, flags); } else { dest.writeInt(0); } } private AssociationInfo(@NonNull Parcel in) { Loading @@ -420,6 +449,11 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = in.readLong(); mLastTimeConnectedMs = in.readLong(); mSystemDataSyncFlags = in.readInt(); if (in.readInt() == 1) { mDeviceIcon = Icon.CREATOR.createFromParcel(in); } else { mDeviceIcon = null; } } @NonNull Loading Loading @@ -459,6 +493,7 @@ public final class AssociationInfo implements Parcelable { private long mTimeApprovedMs; private long mLastTimeConnectedMs; private int mSystemDataSyncFlags; private Icon mDeviceIcon; /** @hide */ @TestApi Loading Loading @@ -486,6 +521,7 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = info.mTimeApprovedMs; mLastTimeConnectedMs = info.mLastTimeConnectedMs; mSystemDataSyncFlags = info.mSystemDataSyncFlags; mDeviceIcon = info.mDeviceIcon; } /** Loading @@ -510,6 +546,7 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = info.mTimeApprovedMs; mLastTimeConnectedMs = info.mLastTimeConnectedMs; mSystemDataSyncFlags = info.mSystemDataSyncFlags; mDeviceIcon = info.mDeviceIcon; } /** @hide */ Loading Loading @@ -622,6 +659,16 @@ public final class AssociationInfo implements Parcelable { return this; } /** @hide */ @TestApi @NonNull @SuppressLint("MissingGetterMatchingBuilder") @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON) public Builder setDeviceIcon(@Nullable Icon deviceIcon) { mDeviceIcon = deviceIcon; return this; } /** @hide */ @TestApi @NonNull Loading @@ -648,7 +695,8 @@ public final class AssociationInfo implements Parcelable { mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags mSystemDataSyncFlags, mDeviceIcon ); } } Loading
core/java/android/companion/AssociationRequest.java +60 −4 Original line number Diff line number Diff line Loading @@ -23,12 +23,14 @@ import static com.android.internal.util.CollectionUtils.emptyIfNull; import static java.util.Objects.requireNonNull; import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.StringDef; import android.annotation.UserIdInt; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.drawable.Icon; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -233,6 +235,13 @@ public final class AssociationRequest implements Parcelable { */ private boolean mSkipPrompt; /** * The device icon displayed in selfManaged association dialog. * @hide */ @Nullable private Icon mDeviceIcon; /** * Creates a new AssociationRequest. * Loading @@ -258,15 +267,16 @@ public final class AssociationRequest implements Parcelable { @Nullable @DeviceProfile String deviceProfile, @Nullable CharSequence displayName, boolean selfManaged, boolean forceConfirmation) { boolean forceConfirmation, @Nullable Icon deviceIcon) { mSingleDevice = singleDevice; mDeviceFilters = requireNonNull(deviceFilters); mDeviceProfile = deviceProfile; mDisplayName = displayName; mSelfManaged = selfManaged; mForceConfirmation = forceConfirmation; mCreationTime = System.currentTimeMillis(); mDeviceIcon = deviceIcon; } /** Loading Loading @@ -318,6 +328,19 @@ public final class AssociationRequest implements Parcelable { return mSingleDevice; } /** * Get the device icon of the self-managed association request. * * @return the device icon, or {@code null} if no device icon has been set. * * @see Builder#setDeviceIcon(Icon) */ @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON) @Nullable public Icon getDeviceIcon() { return mDeviceIcon; } /** @hide */ public void setPackageName(@NonNull String packageName) { mPackageName = packageName; Loading Loading @@ -365,6 +388,7 @@ public final class AssociationRequest implements Parcelable { private CharSequence mDisplayName; private boolean mSelfManaged = false; private boolean mForceConfirmation = false; private Icon mDeviceIcon = null; public Builder() {} Loading Loading @@ -450,6 +474,23 @@ public final class AssociationRequest implements Parcelable { return this; } /** * Set the device icon for the self-managed device and this icon will be * displayed in the self-managed association dialog. * * @throws IllegalArgumentException if the icon is not exactly 24dp by 24dp * or if it is {@link Icon#TYPE_URI} or {@link Icon#TYPE_URI_ADAPTIVE_BITMAP}. * @see #setSelfManaged(boolean) */ @NonNull @RequiresPermission(REQUEST_COMPANION_SELF_MANAGED) @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON) public Builder setDeviceIcon(@NonNull Icon deviceIcon) { checkNotUsed(); mDeviceIcon = requireNonNull(deviceIcon); return this; } /** @inheritDoc */ @NonNull @Override Loading @@ -460,7 +501,7 @@ public final class AssociationRequest implements Parcelable { + "provide the display name of the device"); } return new AssociationRequest(mSingleDevice, emptyIfNull(mDeviceFilters), mDeviceProfile, mDisplayName, mSelfManaged, mForceConfirmation); mDeviceProfile, mDisplayName, mSelfManaged, mForceConfirmation, mDeviceIcon); } } Loading Loading @@ -561,7 +602,9 @@ public final class AssociationRequest implements Parcelable { && Objects.equals(mDeviceProfilePrivilegesDescription, that.mDeviceProfilePrivilegesDescription) && mCreationTime == that.mCreationTime && mSkipPrompt == that.mSkipPrompt; && mSkipPrompt == that.mSkipPrompt && (mDeviceIcon == null ? that.mDeviceIcon == null : mDeviceIcon.sameAs(that.mDeviceIcon)); } @Override Loading @@ -579,6 +622,8 @@ public final class AssociationRequest implements Parcelable { _hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription); _hash = 31 * _hash + Long.hashCode(mCreationTime); _hash = 31 * _hash + Boolean.hashCode(mSkipPrompt); _hash = 31 * _hash + Objects.hashCode(mDeviceIcon); return _hash; } Loading Loading @@ -606,6 +651,12 @@ public final class AssociationRequest implements Parcelable { dest.writeString8(mDeviceProfilePrivilegesDescription); } dest.writeLong(mCreationTime); if (mDeviceIcon != null) { dest.writeInt(1); mDeviceIcon.writeToParcel(dest, flags); } else { dest.writeInt(0); } } @Override Loading Loading @@ -650,6 +701,11 @@ public final class AssociationRequest implements Parcelable { this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription; this.mCreationTime = creationTime; this.mSkipPrompt = skipPrompt; if (in.readInt() == 1) { mDeviceIcon = Icon.CREATOR.createFromParcel(in); } else { mDeviceIcon = null; } } @NonNull Loading
core/java/android/companion/CompanionDeviceManager.java +44 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMIN import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION; import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER; import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH; import static android.graphics.drawable.Icon.TYPE_URI; import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP; import android.annotation.CallbackExecutor; Loading Loading @@ -49,6 +51,11 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.VectorDrawable; import android.net.MacAddress; import android.os.Binder; import android.os.Handler; Loading Loading @@ -535,6 +542,13 @@ public final class CompanionDeviceManager { Objects.requireNonNull(executor, "Executor cannot be null"); Objects.requireNonNull(callback, "Callback cannot be null"); final Icon deviceIcon = request.getDeviceIcon(); if (deviceIcon != null && !isValidIcon(deviceIcon, mContext)) { throw new IllegalArgumentException("The size of the device icon must be 24dp x 24dp to" + "ensure proper display"); } try { mService.associate(request, new AssociationRequestCallbackProxy(executor, callback), mContext.getOpPackageName(), mContext.getUserId()); Loading Loading @@ -2027,4 +2041,34 @@ public final class CompanionDeviceManager { } } } private boolean isValidIcon(Icon icon, Context context) { if (icon.getType() == TYPE_URI_ADAPTIVE_BITMAP || icon.getType() == TYPE_URI) { throw new IllegalArgumentException("The URI based Icon is not supported."); } Drawable drawable = icon.loadDrawable(context); float density = context.getResources().getDisplayMetrics().density; if (drawable instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); float widthDp = bitmap.getWidth() / density; float heightDp = bitmap.getHeight() / density; if (widthDp != 24 || heightDp != 24) { return false; } } else if (drawable instanceof VectorDrawable) { VectorDrawable vectorDrawable = (VectorDrawable) drawable; float widthDp = vectorDrawable.getIntrinsicWidth() / density; float heightDp = vectorDrawable.getIntrinsicHeight() / density; if (widthDp != 24 || heightDp != 24) { return false; } } else { throw new IllegalArgumentException("The format of the device icon is unsupported."); } return true; } }