Update context sync adb commands

Bug: 280604855
Test: n/a
Change-Id: I253a1ea6a13c4f7fab877f6ecdb209079f40992a
This commit is contained in:
Christine Franks
2023-05-10 15:23:05 +00:00
parent b22697f14c
commit 2d454c0b37
3 changed files with 110 additions and 46 deletions

View File

@@ -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)

View File

@@ -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();
}
}

View File

@@ -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.
*