1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.uwb.multchip; 18 19 import android.content.Context; 20 import android.util.Log; 21 22 import com.android.uwb.ChipGroupInfo; 23 import com.android.uwb.ChipInfo; 24 import com.android.uwb.Coordinates; 25 import com.android.uwb.UwbChipConfig; 26 import com.android.uwb.XmlParser; 27 import com.android.uwb.resources.R; 28 29 import com.google.common.base.Strings; 30 import com.google.uwb.support.multichip.ChipInfoParams; 31 32 import org.xmlpull.v1.XmlPullParserException; 33 34 import java.io.BufferedInputStream; 35 import java.io.FileInputStream; 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.stream.Collectors; 41 42 import javax.xml.datatype.DatatypeConfigurationException; 43 44 /** 45 * Manages UWB chip information (such as id and position) for a multi-chip device. 46 */ 47 public class UwbMultichipData { 48 private static final String TAG = "UwbMultichipData"; 49 private final Context mContext; 50 private String mDefaultChipId = "default"; 51 private List<ChipInfoParams> mChipInfoParamsList = 52 List.of(ChipInfoParams.createBuilder().setChipId(mDefaultChipId).build()); 53 private List<String> mChipIds = List.of(mDefaultChipId); 54 private OnInitializedListener mListener; 55 UwbMultichipData(Context context)56 public UwbMultichipData(Context context) { 57 mContext = context; 58 } 59 60 /** 61 * Reads in a configuration file to initialize chip info, if the device is a multi-chip system 62 * a configuration file is defined and available. 63 * 64 * <p>If the device is single-chip, or if no configuration file is available, default values are 65 * used. 66 */ initialize()67 public void initialize() { 68 if (mContext.getResources().getBoolean(R.bool.config_isMultichip)) { 69 String filePath = 70 mContext.getResources().getString(R.string.config_multichipConfigPath); 71 if (Strings.isNullOrEmpty(filePath)) { 72 Log.w(TAG, "Multichip is set to true, but configuration file is not defined."); 73 } else { 74 readConfigurationFile(filePath); 75 } 76 } 77 if (mListener != null) { 78 mListener.onInitialized(); 79 } 80 } 81 82 /** 83 * Returns a list of UWB chip infos in a {@link ChipInfoParams} object. 84 * 85 * Callers can invoke methods on a specific UWB chip by passing its {@code chipId} to the 86 * method, which can be determined by calling: 87 * <pre> 88 * {@code 89 * List<ChipInfoParams> chipInfos = getChipInfos(); 90 * for (ChipInfoParams chipInfo : chipInfos) { 91 * String chipId = chipInfo.getChipId(); 92 * } 93 * } 94 * </pre> 95 * 96 * @return list of {@link ChipInfoParams} containing info about UWB chips for a multi-HAL 97 * system, or a list of info for a single chip for a single HAL system. 98 */ getChipInfos()99 public List<ChipInfoParams> getChipInfos() { 100 return mChipInfoParamsList; 101 } 102 103 /** 104 * Convenience method that returns a list of UWB chip ids. 105 * 106 * @return List of UWB chip ids 107 */ getChipIds()108 public List<String> getChipIds() { 109 return mChipIds; 110 } 111 112 /** 113 * Returns the default UWB chip identifier. 114 * 115 * If callers do not pass a specific {@code chipId} to UWB methods, then the method will be 116 * invoked on the default chip, which is determined at system initialization from a 117 * configuration file. 118 * 119 * @return default UWB chip identifier for a multi-HAL system, or the identifier of the only UWB 120 * chip in a single HAL system. 121 */ getDefaultChipId()122 public String getDefaultChipId() { 123 return mDefaultChipId; 124 } 125 126 /** 127 * Sets an {@link OnInitializedListener}. 128 */ setOnInitializedListener(OnInitializedListener listener)129 public void setOnInitializedListener(OnInitializedListener listener) { 130 mListener = listener; 131 } 132 readConfigurationFile(String filePath)133 private void readConfigurationFile(String filePath) { 134 InputStream stream = null; 135 try { 136 stream = new BufferedInputStream(new FileInputStream(filePath)); 137 UwbChipConfig uwbChipConfig = XmlParser.read(stream); 138 mDefaultChipId = uwbChipConfig.getDefaultChipId(); 139 Log.d(TAG, "Default chip id is " + mDefaultChipId); 140 // Reset mChipInfoParamsList so that it can be populated with values from configuration 141 // file. 142 mChipInfoParamsList = new ArrayList<>(); 143 List<ChipGroupInfo> chipGroups = uwbChipConfig.getChipGroup(); 144 for (ChipGroupInfo chipGroup : chipGroups) { 145 List<ChipInfo> chips = chipGroup.getChip(); 146 for (ChipInfo chip : chips) { 147 String chipId = chip.getId(); 148 Coordinates position = chip.getPosition(); 149 double x, y, z; 150 if (position == null) { 151 x = 0.0; 152 y = 0.0; 153 z = 0.0; 154 } else { 155 x = position.getX() == null ? 0.0 : position.getX().doubleValue(); 156 y = position.getY() == null ? 0.0 : position.getY().doubleValue(); 157 z = position.getZ() == null ? 0.0 : position.getZ().doubleValue(); 158 } 159 Log.d(TAG, 160 "Chip with id " + chipId + " has position " + x + ", " + y + ", " + z); 161 mChipInfoParamsList 162 .add(ChipInfoParams.createBuilder() 163 .setChipId(chipId) 164 .setPositionX(x) 165 .setPositionY(y) 166 .setPositionZ(z).build()); 167 } 168 } 169 mChipIds = mChipInfoParamsList.stream().map(ChipInfoParams::getChipId).collect( 170 Collectors.toUnmodifiableList()); 171 } catch (XmlPullParserException | IOException | DatatypeConfigurationException e) { 172 Log.e(TAG, "Cannot read file " + filePath, e); 173 } finally { 174 try { 175 if (stream != null) 176 stream.close(); 177 } catch (IOException e) { 178 Log.e(TAG, "Cannot close file " + filePath, e); 179 } 180 } 181 } 182 183 /** 184 * Listener for initialization of {@link UwbMultichipData}. 185 */ 186 public interface OnInitializedListener { 187 /** 188 * Invoked by {@link UwbMultichipData#initialize()}. 189 */ onInitialized()190 void onInitialized(); 191 } 192 } 193