Merge "Add and update cross device sync data holders" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ad2e7289cf
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.annotation.NonNull;
|
||||
import android.companion.ContextSyncMessage;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/** A read-only snapshot of an {@link ContextSyncMessage}. */
|
||||
class CallMetadataSyncData {
|
||||
|
||||
final Map<Long, CallMetadataSyncData.Call> mCalls = new HashMap<>();
|
||||
final List<CallMetadataSyncData.Call> mRequests = new ArrayList<>();
|
||||
|
||||
public void addCall(CallMetadataSyncData.Call call) {
|
||||
mCalls.put(call.getId(), call);
|
||||
}
|
||||
|
||||
public boolean hasCall(long id) {
|
||||
return mCalls.containsKey(id);
|
||||
}
|
||||
|
||||
public Collection<CallMetadataSyncData.Call> getCalls() {
|
||||
return mCalls.values();
|
||||
}
|
||||
|
||||
public void addRequest(CallMetadataSyncData.Call call) {
|
||||
mRequests.add(call);
|
||||
}
|
||||
|
||||
public List<CallMetadataSyncData.Call> getRequests() {
|
||||
return mRequests;
|
||||
}
|
||||
|
||||
public static class Call implements Parcelable {
|
||||
private long mId;
|
||||
private String mCallerId;
|
||||
private byte[] mAppIcon;
|
||||
private String mAppName;
|
||||
private String mAppIdentifier;
|
||||
private int mStatus;
|
||||
private final Set<Integer> mControls = new HashSet<>();
|
||||
|
||||
public static Call fromParcel(Parcel parcel) {
|
||||
final Call call = new Call();
|
||||
call.setId(parcel.readLong());
|
||||
call.setCallerId(parcel.readString());
|
||||
call.setAppIcon(parcel.readBlob());
|
||||
call.setAppName(parcel.readString());
|
||||
call.setAppIdentifier(parcel.readString());
|
||||
call.setStatus(parcel.readInt());
|
||||
final int numberOfControls = parcel.readInt();
|
||||
for (int i = 0; i < numberOfControls; i++) {
|
||||
call.addControl(parcel.readInt());
|
||||
}
|
||||
return call;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int parcelableFlags) {
|
||||
parcel.writeLong(mId);
|
||||
parcel.writeString(mCallerId);
|
||||
parcel.writeBlob(mAppIcon);
|
||||
parcel.writeString(mAppName);
|
||||
parcel.writeString(mAppIdentifier);
|
||||
parcel.writeInt(mStatus);
|
||||
parcel.writeInt(mControls.size());
|
||||
for (int control : mControls) {
|
||||
parcel.writeInt(control);
|
||||
}
|
||||
}
|
||||
|
||||
void setId(long id) {
|
||||
mId = id;
|
||||
}
|
||||
|
||||
void setCallerId(String callerId) {
|
||||
mCallerId = callerId;
|
||||
}
|
||||
|
||||
void setAppIcon(byte[] appIcon) {
|
||||
mAppIcon = appIcon;
|
||||
}
|
||||
|
||||
void setAppName(String appName) {
|
||||
mAppName = appName;
|
||||
}
|
||||
|
||||
void setAppIdentifier(String appIdentifier) {
|
||||
mAppIdentifier = appIdentifier;
|
||||
}
|
||||
|
||||
void setStatus(int status) {
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
void addControl(int control) {
|
||||
mControls.add(control);
|
||||
}
|
||||
|
||||
long getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
String getCallerId() {
|
||||
return mCallerId;
|
||||
}
|
||||
|
||||
byte[] getAppIcon() {
|
||||
return mAppIcon;
|
||||
}
|
||||
|
||||
String getAppName() {
|
||||
return mAppName;
|
||||
}
|
||||
|
||||
String getAppIdentifier() {
|
||||
return mAppIdentifier;
|
||||
}
|
||||
|
||||
int getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
Set<Integer> getControls() {
|
||||
return mControls;
|
||||
}
|
||||
|
||||
boolean hasControl(int control) {
|
||||
return mControls.contains(control);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof CallMetadataSyncData.Call) {
|
||||
return ((Call) other).getId() == getId();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(mId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NonNull public static final Parcelable.Creator<Call> CREATOR = new Parcelable.Creator<>() {
|
||||
|
||||
@Override
|
||||
public Call createFromParcel(Parcel source) {
|
||||
return Call.fromParcel(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Call[] newArray(int size) {
|
||||
return new Call[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,8 @@ public class CrossDeviceCall {
|
||||
|
||||
private static final String TAG = "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 static final AtomicLong sNextId = new AtomicLong(1);
|
||||
@@ -47,6 +49,7 @@ public class CrossDeviceCall {
|
||||
private final Call mCall;
|
||||
@VisibleForTesting boolean mIsEnterprise;
|
||||
@VisibleForTesting boolean mIsOtt;
|
||||
private final String mCallingAppPackageName;
|
||||
private String mCallingAppName;
|
||||
private byte[] mCallingAppIcon;
|
||||
private String mCallerDisplayName;
|
||||
@@ -59,7 +62,7 @@ public class CrossDeviceCall {
|
||||
CallAudioState callAudioState) {
|
||||
mId = sNextId.getAndIncrement();
|
||||
mCall = call;
|
||||
final String callingAppPackageName = call != null
|
||||
mCallingAppPackageName = call != null
|
||||
? call.getDetails().getAccountHandle().getComponentName().getPackageName() : null;
|
||||
mIsOtt = call != null
|
||||
&& (call.getDetails().getCallCapabilities() & Call.Details.PROPERTY_SELF_MANAGED)
|
||||
@@ -69,13 +72,13 @@ public class CrossDeviceCall {
|
||||
== Call.Details.PROPERTY_ENTERPRISE_CALL;
|
||||
try {
|
||||
final ApplicationInfo applicationInfo = packageManager
|
||||
.getApplicationInfo(callingAppPackageName,
|
||||
.getApplicationInfo(mCallingAppPackageName,
|
||||
PackageManager.ApplicationInfoFlags.of(0));
|
||||
mCallingAppName = packageManager.getApplicationLabel(applicationInfo).toString();
|
||||
mCallingAppIcon = renderDrawableToByteArray(
|
||||
packageManager.getApplicationIcon(applicationInfo));
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.e(TAG, "Could not get application info for package " + callingAppPackageName, e);
|
||||
Slog.e(TAG, "Could not get application info for package " + mCallingAppPackageName, e);
|
||||
}
|
||||
mIsMuted = callAudioState != null && callAudioState.isMuted();
|
||||
if (call != null) {
|
||||
@@ -170,7 +173,8 @@ public class CrossDeviceCall {
|
||||
}
|
||||
}
|
||||
|
||||
private int convertStateToStatus(int callState) {
|
||||
/** Converts a Telecom call state to a Context Sync status. */
|
||||
public static int convertStateToStatus(int callState) {
|
||||
switch (callState) {
|
||||
case Call.STATE_HOLDING:
|
||||
return android.companion.Telecom.Call.ON_HOLD;
|
||||
@@ -178,20 +182,30 @@ public class CrossDeviceCall {
|
||||
return android.companion.Telecom.Call.ONGOING;
|
||||
case Call.STATE_RINGING:
|
||||
return android.companion.Telecom.Call.RINGING;
|
||||
case Call.STATE_NEW:
|
||||
case Call.STATE_DIALING:
|
||||
case Call.STATE_DISCONNECTED:
|
||||
case Call.STATE_SELECT_PHONE_ACCOUNT:
|
||||
case Call.STATE_CONNECTING:
|
||||
case Call.STATE_DISCONNECTING:
|
||||
case Call.STATE_PULLING_CALL:
|
||||
case Call.STATE_AUDIO_PROCESSING:
|
||||
case Call.STATE_SIMULATED_RINGING:
|
||||
default:
|
||||
return android.companion.Telecom.Call.UNKNOWN_STATUS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Context Sync status to a Telecom call state. Note that this is lossy for
|
||||
* and RINGING_SILENCED, as Telecom does not distinguish between RINGING and RINGING_SILENCED.
|
||||
*/
|
||||
public static int convertStatusToState(int status) {
|
||||
switch (status) {
|
||||
case android.companion.Telecom.Call.ON_HOLD:
|
||||
return Call.STATE_HOLDING;
|
||||
case android.companion.Telecom.Call.ONGOING:
|
||||
return Call.STATE_ACTIVE;
|
||||
case android.companion.Telecom.Call.RINGING:
|
||||
case android.companion.Telecom.Call.RINGING_SILENCED:
|
||||
return Call.STATE_RINGING;
|
||||
case android.companion.Telecom.Call.UNKNOWN_STATUS:
|
||||
default:
|
||||
return Call.STATE_NEW;
|
||||
}
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return mId;
|
||||
}
|
||||
@@ -208,6 +222,10 @@ public class CrossDeviceCall {
|
||||
return mCallingAppIcon;
|
||||
}
|
||||
|
||||
public String getCallingAppPackageName() {
|
||||
return mCallingAppPackageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a human-readable "caller id" to display as the origin of the call.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class CallMetadataSyncDataTest {
|
||||
|
||||
@Test
|
||||
public void call_writeToParcel_fromParcel_reconstructsSuccessfully() {
|
||||
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
|
||||
final long id = 5;
|
||||
final String callerId = "callerId";
|
||||
final byte[] appIcon = "appIcon".getBytes();
|
||||
final String appName = "appName";
|
||||
final String appIdentifier = "com.google.test";
|
||||
final int status = 1;
|
||||
final int control1 = 2;
|
||||
final int control2 = 3;
|
||||
call.setId(id);
|
||||
call.setCallerId(callerId);
|
||||
call.setAppIcon(appIcon);
|
||||
call.setAppName(appName);
|
||||
call.setAppIdentifier(appIdentifier);
|
||||
call.setStatus(status);
|
||||
call.addControl(control1);
|
||||
call.addControl(control2);
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
call.writeToParcel(parcel, /* flags= */ 0);
|
||||
parcel.setDataPosition(0);
|
||||
final CallMetadataSyncData.Call reconstructedCall = CallMetadataSyncData.Call.fromParcel(
|
||||
parcel);
|
||||
|
||||
assertThat(reconstructedCall.getId()).isEqualTo(id);
|
||||
assertThat(reconstructedCall.getCallerId()).isEqualTo(callerId);
|
||||
assertThat(reconstructedCall.getAppIcon()).isEqualTo(appIcon);
|
||||
assertThat(reconstructedCall.getAppName()).isEqualTo(appName);
|
||||
assertThat(reconstructedCall.getAppIdentifier()).isEqualTo(appIdentifier);
|
||||
assertThat(reconstructedCall.getStatus()).isEqualTo(status);
|
||||
assertThat(reconstructedCall.getControls()).containsExactly(control1, control2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user