Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5856b63 authored by Christine Franks's avatar Christine Franks Committed by Automerger Merge Worker
Browse files

Merge "Update context sync adb commands" into udc-dev am: 1e1ead7e

parents f2e8151c 1e1ead7e
Loading
Loading
Loading
Loading
+44 −5
Original line number Diff line number Diff line
@@ -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.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)
+65 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}
+1 −41
Original line number Diff line number Diff line
@@ -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.
     *