diff options
3 files changed, 110 insertions, 46 deletions
| diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java index c511429a37d8..04fbab434d1f 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java @@ -26,6 +26,7 @@ import android.os.ShellCommand;  import android.util.proto.ProtoOutputStream;  import com.android.server.companion.datatransfer.SystemDataTransferRequestStore; +import com.android.server.companion.datatransfer.contextsync.BitmapUtils;  import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;  import com.android.server.companion.presence.CompanionDevicePresenceMonitor;  import com.android.server.companion.transport.CompanionTransportManager; @@ -168,13 +169,17 @@ class CompanionDeviceShellCommand extends ShellCommand {                  case "send-context-sync-call-facilitators-message": {                      associationId = getNextIntArgRequired();                      int numberOfFacilitators = getNextIntArgRequired(); +                    String facilitatorName = getNextArgRequired(); +                    String facilitatorId = getNextArgRequired();                      final ProtoOutputStream pos = new ProtoOutputStream();                      pos.write(ContextSyncMessage.VERSION, 1);                      final long telecomToken = pos.start(ContextSyncMessage.TELECOM);                      for (int i = 0; i < numberOfFacilitators; i++) {                          final long facilitatorsToken = pos.start(Telecom.FACILITATORS); -                        pos.write(Telecom.CallFacilitator.NAME, "Call Facilitator App #" + i); -                        pos.write(Telecom.CallFacilitator.IDENTIFIER, "com.android.test" + i); +                        pos.write(Telecom.CallFacilitator.NAME, +                                numberOfFacilitators == 1 ? facilitatorName : facilitatorName + i); +                        pos.write(Telecom.CallFacilitator.IDENTIFIER, +                                numberOfFacilitators == 1 ? facilitatorId : facilitatorId + i);                          pos.end(facilitatorsToken);                      }                      pos.end(telecomToken); @@ -188,6 +193,15 @@ class CompanionDeviceShellCommand extends ShellCommand {                      associationId = getNextIntArgRequired();                      String callId = getNextArgRequired();                      String facilitatorId = getNextArgRequired(); +                    int status = getNextIntArgRequired(); +                    boolean acceptControl = getNextBooleanArgRequired(); +                    boolean rejectControl = getNextBooleanArgRequired(); +                    boolean silenceControl = getNextBooleanArgRequired(); +                    boolean muteControl = getNextBooleanArgRequired(); +                    boolean unmuteControl = getNextBooleanArgRequired(); +                    boolean endControl = getNextBooleanArgRequired(); +                    boolean holdControl = getNextBooleanArgRequired(); +                    boolean unholdControl = getNextBooleanArgRequired();                      final ProtoOutputStream pos = new ProtoOutputStream();                      pos.write(ContextSyncMessage.VERSION, 1);                      final long telecomToken = pos.start(ContextSyncMessage.TELECOM); @@ -195,15 +209,40 @@ class CompanionDeviceShellCommand extends ShellCommand {                      pos.write(Telecom.Call.ID, callId);                      final long originToken = pos.start(Telecom.Call.ORIGIN);                      pos.write(Telecom.Call.Origin.CALLER_ID, "Caller Name"); +                    pos.write(Telecom.Call.Origin.APP_ICON, BitmapUtils.renderDrawableToByteArray( +                            mService.getContext().getPackageManager().getApplicationIcon( +                                    facilitatorId)));                      final long facilitatorToken = pos.start(                              Telecom.Request.CreateAction.FACILITATOR);                      pos.write(Telecom.CallFacilitator.NAME, "Test App Name");                      pos.write(Telecom.CallFacilitator.IDENTIFIER, facilitatorId);                      pos.end(facilitatorToken);                      pos.end(originToken); -                    pos.write(Telecom.Call.STATUS, Telecom.Call.RINGING); -                    pos.write(Telecom.Call.CONTROLS, Telecom.ACCEPT); -                    pos.write(Telecom.Call.CONTROLS, Telecom.REJECT); +                    pos.write(Telecom.Call.STATUS, status); +                    if (acceptControl) { +                        pos.write(Telecom.Call.CONTROLS, Telecom.ACCEPT); +                    } +                    if (rejectControl) { +                        pos.write(Telecom.Call.CONTROLS, Telecom.REJECT); +                    } +                    if (silenceControl) { +                        pos.write(Telecom.Call.CONTROLS, Telecom.SILENCE); +                    } +                    if (muteControl) { +                        pos.write(Telecom.Call.CONTROLS, Telecom.MUTE); +                    } +                    if (unmuteControl) { +                        pos.write(Telecom.Call.CONTROLS, Telecom.UNMUTE); +                    } +                    if (endControl) { +                        pos.write(Telecom.Call.CONTROLS, Telecom.END); +                    } +                    if (holdControl) { +                        pos.write(Telecom.Call.CONTROLS, Telecom.PUT_ON_HOLD); +                    } +                    if (unholdControl) { +                        pos.write(Telecom.Call.CONTROLS, Telecom.TAKE_OFF_HOLD); +                    }                      pos.end(callsToken);                      pos.end(telecomToken);                      mTransportManager.createEmulatedTransport(associationId) diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/BitmapUtils.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/BitmapUtils.java new file mode 100644 index 000000000000..829041af2198 --- /dev/null +++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/BitmapUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.companion.datatransfer.contextsync; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +import java.io.ByteArrayOutputStream; + +/** Provides bitmap utility operations for rendering drawables to byte arrays. */ +public class BitmapUtils { + +    private static final int APP_ICON_BITMAP_DIMENSION = 256; + +    /** Render a drawable to a bitmap, which is then reformatted as a byte array. */ +    public static byte[] renderDrawableToByteArray(Drawable drawable) { +        if (drawable instanceof BitmapDrawable) { +            // Can't recycle the drawable's bitmap, so handle separately +            final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); +            if (bitmap.getWidth() > APP_ICON_BITMAP_DIMENSION +                    || bitmap.getHeight() > APP_ICON_BITMAP_DIMENSION) { +                // Downscale, as the original drawable bitmap is too large. +                final Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, +                        APP_ICON_BITMAP_DIMENSION, APP_ICON_BITMAP_DIMENSION, /* filter= */ true); +                final byte[] renderedBitmap = renderBitmapToByteArray(scaledBitmap); +                scaledBitmap.recycle(); +                return renderedBitmap; +            } +            return renderBitmapToByteArray(bitmap); +        } +        final Bitmap bitmap = Bitmap.createBitmap(APP_ICON_BITMAP_DIMENSION, +                APP_ICON_BITMAP_DIMENSION, +                Bitmap.Config.ARGB_8888); +        try { +            final Canvas canvas = new Canvas(bitmap); +            drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); +            drawable.draw(canvas); +            return renderBitmapToByteArray(bitmap); +        } finally { +            bitmap.recycle(); +        } +    } + +    private static byte[] renderBitmapToByteArray(Bitmap bitmap) { +        final ByteArrayOutputStream baos = new ByteArrayOutputStream(bitmap.getByteCount()); +        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); +        return baos.toByteArray(); +    } +} diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java index 168068ec6497..de7bf4022e04 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java +++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java @@ -19,10 +19,6 @@ package com.android.server.companion.datatransfer.contextsync;  import android.annotation.NonNull;  import android.content.pm.ApplicationInfo;  import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable;  import android.telecom.Call;  import android.telecom.CallAudioState;  import android.telecom.VideoProfile; @@ -30,7 +26,6 @@ import android.util.Slog;  import com.android.internal.annotations.VisibleForTesting; -import java.io.ByteArrayOutputStream;  import java.util.HashSet;  import java.util.Set;  import java.util.UUID; @@ -42,7 +37,6 @@ public class CrossDeviceCall {      public static final String EXTRA_CALL_ID =              "com.android.companion.datatransfer.contextsync.extra.CALL_ID"; -    private static final int APP_ICON_BITMAP_DIMENSION = 256;      private final String mId;      private Call mCall; @@ -80,7 +74,7 @@ public class CrossDeviceCall {                      .getApplicationInfo(mCallingAppPackageName,                              PackageManager.ApplicationInfoFlags.of(0));              mCallingAppName = packageManager.getApplicationLabel(applicationInfo).toString(); -            mCallingAppIcon = renderDrawableToByteArray( +            mCallingAppIcon = BitmapUtils.renderDrawableToByteArray(                      packageManager.getApplicationIcon(applicationInfo));          } catch (PackageManager.NameNotFoundException e) {              Slog.e(TAG, "Could not get application info for package " + mCallingAppPackageName, e); @@ -89,40 +83,6 @@ public class CrossDeviceCall {          updateCallDetails(callDetails);      } -    private byte[] renderDrawableToByteArray(Drawable drawable) { -        if (drawable instanceof BitmapDrawable) { -            // Can't recycle the drawable's bitmap, so handle separately -            final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); -            if (bitmap.getWidth() > APP_ICON_BITMAP_DIMENSION -                    || bitmap.getHeight() > APP_ICON_BITMAP_DIMENSION) { -                // Downscale, as the original drawable bitmap is too large. -                final Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, -                        APP_ICON_BITMAP_DIMENSION, APP_ICON_BITMAP_DIMENSION, /* filter= */ true); -                final byte[] renderedBitmap = renderBitmapToByteArray(scaledBitmap); -                scaledBitmap.recycle(); -                return renderedBitmap; -            } -            return renderBitmapToByteArray(bitmap); -        } -        final Bitmap bitmap = Bitmap.createBitmap(APP_ICON_BITMAP_DIMENSION, -                APP_ICON_BITMAP_DIMENSION, -                Bitmap.Config.ARGB_8888); -        try { -            final Canvas canvas = new Canvas(bitmap); -            drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); -            drawable.draw(canvas); -            return renderBitmapToByteArray(bitmap); -        } finally { -            bitmap.recycle(); -        } -    } - -    private byte[] renderBitmapToByteArray(Bitmap bitmap) { -        final ByteArrayOutputStream baos = new ByteArrayOutputStream(bitmap.getByteCount()); -        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); -        return baos.toByteArray(); -    } -      /**       * Update the mute state of this call. No-op if the call is not capable of being muted.       * |