blob: 2e3be42f22f2c3303e4cad323b55addcaab1b118 [file] [log] [blame]
/*
* Copyright (C) 2021 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.uwb;
import android.annotation.NonNull;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.util.Log;
import android.uwb.AngleMeasurement;
import android.uwb.AngleOfArrivalMeasurement;
import android.uwb.DistanceMeasurement;
import android.uwb.IUwbRangingCallbacks;
import android.uwb.RangingChangeReason;
import android.uwb.RangingMeasurement;
import android.uwb.RangingReport;
import android.uwb.SessionHandle;
import android.uwb.UwbAddress;
import com.android.server.uwb.UwbSessionManager.UwbSession;
import com.android.server.uwb.data.UwbRangingData;
import com.android.server.uwb.data.UwbTwoWayMeasurement;
import com.android.server.uwb.data.UwbUciConstants;
import com.android.server.uwb.params.TlvUtil;
import com.android.server.uwb.util.UwbUtil;
import com.google.uwb.support.base.Params;
import com.google.uwb.support.ccc.CccParams;
import com.google.uwb.support.ccc.CccRangingReconfiguredParams;
import com.google.uwb.support.fira.FiraOpenSessionParams;
import com.google.uwb.support.fira.FiraParams;
import com.google.uwb.support.oemextension.RangingReportMetadata;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class UwbSessionNotificationManager {
private static final String TAG = "UwbSessionNotiManager";
private final UwbInjector mUwbInjector;
public UwbSessionNotificationManager(@NonNull UwbInjector uwbInjector) {
mUwbInjector = uwbInjector;
}
public void onRangingResult(UwbSession uwbSession, UwbRangingData rangingData) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
boolean permissionGranted = mUwbInjector.checkUwbRangingPermissionForDataDelivery(
uwbSession.getAttributionSource(), "uwb ranging result");
if (!permissionGranted) {
Log.e(TAG, "Not delivering ranging result because of permission denial"
+ sessionHandle);
return;
}
RangingReport rangingReport = getRangingReport(rangingData, uwbSession.getProtocolName(),
uwbSession.getParams(), mUwbInjector.getElapsedSinceBootNanos());
if (mUwbInjector.getUwbServiceCore().isOemExtensionCbRegistered()) {
try {
rangingReport = mUwbInjector.getUwbServiceCore().getOemExtensionCallback()
.onRangingReportReceived(rangingReport);
} catch (RemoteException e) {
e.printStackTrace();
}
}
try {
uwbRangingCallbacks.onRangingResult(sessionHandle, rangingReport);
Log.i(TAG, "IUwbRangingCallbacks - onRangingResult");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingResult : Failed");
e.printStackTrace();
}
}
public void onRangingOpened(UwbSession uwbSession) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingOpened(sessionHandle);
Log.i(TAG, "IUwbRangingCallbacks - onRangingOpened");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingOpened : Failed");
e.printStackTrace();
}
}
public void onRangingOpenFailed(UwbSession uwbSession, int status) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingOpenFailed(sessionHandle,
UwbSessionNotificationHelper.convertUciStatusToApiReasonCode(status),
UwbSessionNotificationHelper.convertUciStatusToParam(
uwbSession.getProtocolName(), status));
Log.i(TAG, "IUwbRangingCallbacks - onRangingOpenFailed");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingOpenFailed : Failed");
e.printStackTrace();
}
}
public void onRangingStarted(UwbSession uwbSession, Params rangingStartedParams) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingStarted(sessionHandle, rangingStartedParams.toBundle());
Log.i(TAG, "IUwbRangingCallbacks - onRangingStarted");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingStarted : Failed");
e.printStackTrace();
}
}
public void onRangingStartFailed(UwbSession uwbSession, int status) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingStartFailed(sessionHandle,
UwbSessionNotificationHelper.convertUciStatusToApiReasonCode(status),
UwbSessionNotificationHelper.convertUciStatusToParam(
uwbSession.getProtocolName(), status));
Log.i(TAG, "IUwbRangingCallbacks - onRangingStartFailed");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingStartFailed : Failed");
e.printStackTrace();
}
}
private void onRangingStoppedInternal(UwbSession uwbSession, int reason,
PersistableBundle params) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingStopped(sessionHandle, reason, params);
Log.i(TAG, "IUwbRangingCallbacks - onRangingStopped");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingStopped : Failed");
e.printStackTrace();
}
}
public void onRangingStoppedWithUciReasonCode(UwbSession uwbSession, int reasonCode) {
onRangingStoppedInternal(uwbSession,
UwbSessionNotificationHelper.convertUciReasonCodeToApiReasonCode(reasonCode),
new PersistableBundle());
}
public void onRangingStoppedWithApiReasonCode(
UwbSession uwbSession, @RangingChangeReason int reasonCode) {
onRangingStoppedInternal(uwbSession, reasonCode, new PersistableBundle());
}
public void onRangingStopped(UwbSession uwbSession, int status) {
onRangingStoppedInternal(uwbSession,
UwbSessionNotificationHelper.convertUciStatusToApiReasonCode(
status),
UwbSessionNotificationHelper.convertUciStatusToParam(
uwbSession.getProtocolName(), status));
}
public void onRangingStopFailed(UwbSession uwbSession, int status) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingStopFailed(sessionHandle,
UwbSessionNotificationHelper.convertUciStatusToApiReasonCode(
status),
UwbSessionNotificationHelper.convertUciStatusToParam(
uwbSession.getProtocolName(), status));
Log.i(TAG, "IUwbRangingCallbacks - onRangingStopFailed");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingStopFailed : Failed");
e.printStackTrace();
}
}
public void onRangingReconfigured(UwbSession uwbSession) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
PersistableBundle params;
if (Objects.equals(uwbSession.getProtocolName(), CccParams.PROTOCOL_NAME)) {
// Why are there no params defined for this bundle?
params = new CccRangingReconfiguredParams.Builder().build().toBundle();
} else {
// No params defined for FiRa reconfigure.
params = new PersistableBundle();
}
try {
uwbRangingCallbacks.onRangingReconfigured(sessionHandle, params);
Log.i(TAG, "IUwbRangingCallbacks - onRangingReconfigured");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingReconfigured : Failed");
e.printStackTrace();
}
}
public void onRangingReconfigureFailed(UwbSession uwbSession, int status) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingReconfigureFailed(sessionHandle,
UwbSessionNotificationHelper.convertUciStatusToApiReasonCode(
status),
UwbSessionNotificationHelper.convertUciStatusToParam(
uwbSession.getProtocolName(), status));
Log.i(TAG, "IUwbRangingCallbacks - onRangingReconfigureFailed");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingReconfigureFailed : Failed");
e.printStackTrace();
}
}
public void onControleeAdded(UwbSession uwbSession) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onControleeAdded(sessionHandle, new PersistableBundle());
Log.i(TAG, "IUwbRangingCallbacks - onControleeAdded");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onControleeAdded: Failed");
e.printStackTrace();
}
}
public void onControleeAddFailed(UwbSession uwbSession, int status) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onControleeAddFailed(sessionHandle,
UwbSessionNotificationHelper.convertUciStatusToApiReasonCode(
status),
UwbSessionNotificationHelper.convertUciStatusToParam(
uwbSession.getProtocolName(), status));
Log.i(TAG, "IUwbRangingCallbacks - onControleeAddFailed");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onControleeAddFailed : Failed");
e.printStackTrace();
}
}
public void onControleeRemoved(UwbSession uwbSession) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onControleeRemoved(sessionHandle, new PersistableBundle());
Log.i(TAG, "IUwbRangingCallbacks - onControleeRemoved");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onControleeRemoved: Failed");
e.printStackTrace();
}
}
public void onControleeRemoveFailed(UwbSession uwbSession, int status) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onControleeRemoveFailed(sessionHandle,
UwbSessionNotificationHelper.convertUciStatusToApiReasonCode(
status),
UwbSessionNotificationHelper.convertUciStatusToParam(
uwbSession.getProtocolName(), status));
Log.i(TAG, "IUwbRangingCallbacks - onControleeRemoveFailed");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onControleeRemoveFailed : Failed");
e.printStackTrace();
}
}
public void onRangingClosed(UwbSession uwbSession, int status) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingClosed(sessionHandle,
UwbSessionNotificationHelper.convertUciStatusToApiReasonCode(
status),
UwbSessionNotificationHelper.convertUciStatusToParam(
uwbSession.getProtocolName(), status));
Log.i(TAG, "IUwbRangingCallbacks - onRangingClosed");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingClosed : Failed");
e.printStackTrace();
}
}
public void onRangingClosedWithApiReasonCode(
UwbSession uwbSession, @RangingChangeReason int reasonCode) {
SessionHandle sessionHandle = uwbSession.getSessionHandle();
IUwbRangingCallbacks uwbRangingCallbacks = uwbSession.getIUwbRangingCallbacks();
try {
uwbRangingCallbacks.onRangingClosed(sessionHandle, reasonCode, new PersistableBundle());
Log.i(TAG, "IUwbRangingCallbacks - onRangingClosed");
} catch (Exception e) {
Log.e(TAG, "IUwbRangingCallbacks - onRangingClosed : Failed");
e.printStackTrace();
}
}
private static RangingReport getRangingReport(
@NonNull UwbRangingData rangingData, String protocolName,
Params sessionParams, long elapsedRealtimeNanos) {
if (rangingData.getRangingMeasuresType()
!= UwbUciConstants.RANGING_MEASUREMENT_TYPE_TWO_WAY) {
return null;
}
boolean isAoaAzimuthEnabled = true;
boolean isAoaElevationEnabled = true;
boolean isDestAoaAzimuthEnabled = false;
boolean isDestAoaElevationEnabled = false;
long sessionId = 0;
// For FIRA sessions, check if AOA is enabled for the session or not.
if (protocolName.equals(FiraParams.PROTOCOL_NAME)) {
FiraOpenSessionParams openSessionParams = (FiraOpenSessionParams) sessionParams;
sessionId = openSessionParams.getSessionId();
switch (openSessionParams.getAoaResultRequest()) {
case FiraParams.AOA_RESULT_REQUEST_MODE_NO_AOA_REPORT:
isAoaAzimuthEnabled = false;
isAoaElevationEnabled = false;
break;
case FiraParams.AOA_RESULT_REQUEST_MODE_REQ_AOA_RESULTS:
case FiraParams.AOA_RESULT_REQUEST_MODE_REQ_AOA_RESULTS_INTERLEAVED:
isAoaAzimuthEnabled = true;
isAoaElevationEnabled = true;
break;
case FiraParams.AOA_RESULT_REQUEST_MODE_REQ_AOA_RESULTS_AZIMUTH_ONLY:
isAoaAzimuthEnabled = true;
isAoaElevationEnabled = false;
break;
case FiraParams.AOA_RESULT_REQUEST_MODE_REQ_AOA_RESULTS_ELEVATION_ONLY:
isAoaAzimuthEnabled = false;
isAoaElevationEnabled = true;
break;
default:
throw new IllegalArgumentException("Invalid AOA result req");
}
if (openSessionParams.hasResultReportPhase()) {
if (openSessionParams.hasAngleOfArrivalAzimuthReport()) {
isDestAoaAzimuthEnabled = true;
}
if (openSessionParams.hasAngleOfArrivalElevationReport()) {
isDestAoaElevationEnabled = true;
}
}
}
List<RangingMeasurement> rangingMeasurements = new ArrayList<>();
UwbTwoWayMeasurement[] uwbTwoWayMeasurement = rangingData.getRangingTwoWayMeasures();
for (int i = 0; i < rangingData.getNoOfRangingMeasures(); ++i) {
UwbAddress macAddress = UwbAddress.fromBytes(TlvUtil.getReverseBytes(
uwbTwoWayMeasurement[i].getMacAddress()));
int rangingStatus = uwbTwoWayMeasurement[i].getRangingStatus();
DistanceMeasurement distanceMeasurement = null;
AngleOfArrivalMeasurement angleOfArrivalMeasurement = null;
AngleOfArrivalMeasurement destinationAngleOfArrivalMeasurement = null;
int los = uwbTwoWayMeasurement[i].mNLoS;
int rssi = uwbTwoWayMeasurement[i].getRssi();
if (rangingStatus == FiraParams.STATUS_CODE_OK) {
// Distance measurement is mandatory
distanceMeasurement = new DistanceMeasurement.Builder()
.setMeters(uwbTwoWayMeasurement[i].getDistance() / (double) 100)
.setErrorMeters(0)
// TODO: Need to fetch distance FOM once it is added to UCI spec.
.setConfidenceLevel(0)
.build();
// Aoa measurement is optional based on configuration.
if (isAoaAzimuthEnabled || isAoaElevationEnabled) {
AngleMeasurement azimuthAngleMeasurement = null;
AngleMeasurement altitudeAngleMeasurement = null;
if (isAoaAzimuthEnabled) {
azimuthAngleMeasurement = new AngleMeasurement(
UwbUtil.degreeToRadian(uwbTwoWayMeasurement[i].getAoaAzimuth()),
0, uwbTwoWayMeasurement[i].getAoaAzimuthFom() / (double) 100);
}
if (isAoaElevationEnabled) {
altitudeAngleMeasurement = new AngleMeasurement(
UwbUtil.degreeToRadian(uwbTwoWayMeasurement[i].getAoaElevation()),
0, uwbTwoWayMeasurement[i].getAoaElevationFom() / (double) 100);
}
// AngleOfArrivalMeasurement
angleOfArrivalMeasurement = new AngleOfArrivalMeasurement.Builder(
azimuthAngleMeasurement)
.setAltitude(altitudeAngleMeasurement)
.build();
}
if (isDestAoaAzimuthEnabled || isDestAoaElevationEnabled) {
AngleMeasurement destinationAzimuthAngleMeasurement = null;
AngleMeasurement destinationAltitudeAngleMeasurement = null;
if (isDestAoaAzimuthEnabled) {
destinationAzimuthAngleMeasurement = new AngleMeasurement(
UwbUtil.degreeToRadian(uwbTwoWayMeasurement[i].getAoaDestAzimuth()),
0, uwbTwoWayMeasurement[i].getAoaDestAzimuthFom() / (double) 100);
}
if (isDestAoaElevationEnabled) {
destinationAltitudeAngleMeasurement = new AngleMeasurement(
UwbUtil.degreeToRadian(
uwbTwoWayMeasurement[i].getAoaDestElevation()),
0, uwbTwoWayMeasurement[i].getAoaDestElevationFom() / (double) 100);
}
// Dest AngleOfArrivalMeasurement
destinationAngleOfArrivalMeasurement = new AngleOfArrivalMeasurement.Builder(
destinationAzimuthAngleMeasurement)
.setAltitude(destinationAltitudeAngleMeasurement)
.build();
}
}
RangingMeasurement.Builder rangingMeasurementBuilder = new RangingMeasurement.Builder()
.setRemoteDeviceAddress(macAddress)
.setStatus(rangingStatus)
.setElapsedRealtimeNanos(elapsedRealtimeNanos)
.setDistanceMeasurement(distanceMeasurement)
.setAngleOfArrivalMeasurement(angleOfArrivalMeasurement)
.setDestinationAngleOfArrivalMeasurement(destinationAngleOfArrivalMeasurement)
.setLineOfSight(los);
if (rssi < 0) {
rangingMeasurementBuilder.setRssiDbm(rssi);
}
// TODO: No ranging measurement metadata defined, added for future usage
PersistableBundle rangingMeasurementMetadata = new PersistableBundle();
rangingMeasurementBuilder.setRangingMeasurementMetadata(rangingMeasurementMetadata);
rangingMeasurements.add(rangingMeasurementBuilder.build());
}
PersistableBundle rangingReportMetadata = new RangingReportMetadata.Builder()
.setSessionId(sessionId)
.setRawNtfData(rangingData.getRawNtfData())
.build()
.toBundle();
if (rangingMeasurements.size() == 1) {
return new RangingReport.Builder()
.addMeasurement(rangingMeasurements.get(0))
.addRangingReportMetadata(rangingReportMetadata)
.build();
} else {
return new RangingReport.Builder()
.addMeasurements(rangingMeasurements)
.addRangingReportMetadata(rangingReportMetadata)
.build();
}
}
}