[AA] Added CarInfo tab to Android Auto
Added a new tab for subscribing to and showing CarProperties within Android Auto. The UI handling is a bit sluggish still, but can potentially be imporved further.
This commit is contained in:
@@ -5,14 +5,6 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('/home/aldo270717/AndroidStudioProjects/AldoApps_KeystoreUpload.jks')
|
||||
storePassword 'p49Js5ewYPZbkvhj'
|
||||
keyAlias 'upload'
|
||||
keyPassword 'p49Js5ewYPZbkvhj'
|
||||
}
|
||||
}
|
||||
namespace 'com.aldo.apps.familyhelpers'
|
||||
compileSdk 34
|
||||
|
||||
@@ -29,9 +21,9 @@ android {
|
||||
applicationId "com.aldo.apps.familyhelpers"
|
||||
minSdk 32
|
||||
targetSdk 34
|
||||
versionCode 8
|
||||
versionName "0.2.3"
|
||||
android.buildFeatures.buildConfig true
|
||||
versionCode 12
|
||||
versionName "0.2.7"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@@ -40,6 +32,7 @@ android {
|
||||
signingConfig signingConfigs.myCustomKeystore
|
||||
buildConfigField "String", "GOOGLE_MAPS_API_KEY", "\"${googleMapsApiKeyRelease}\""
|
||||
manifestPlaceholders.google_maps_api_key = googleMapsApiKeyRelease
|
||||
minifyEnabled false
|
||||
}
|
||||
release {
|
||||
signingConfig signingConfigs.myCustomKeystore
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.car.permission.CAR_INFO"/>
|
||||
<uses-permission android:name="com.google.android.gms.permission.CAR_SPEED" />
|
||||
<uses-permission android:name="com.google.android.gms.permission.CAR_FUEL" />
|
||||
<uses-permission android:name="com.google.android.gms.permission.CAR_MILEAGE" />
|
||||
|
||||
<uses-sdk android:minSdkVersion="32"
|
||||
android:targetSdkVersion="34" />
|
||||
@@ -46,7 +48,7 @@
|
||||
android:resource="@xml/automotive_app_desc"/>
|
||||
<meta-data
|
||||
android:name="androidx.car.app.minCarApiLevel"
|
||||
android:value="1" />
|
||||
android:value="3" />
|
||||
|
||||
<activity
|
||||
android:name=".FlashlightActivity"
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.aldo.apps.familyhelpers;
|
||||
|
||||
import static android.Manifest.permission.CAMERA;
|
||||
import static android.Manifest.permission.POST_NOTIFICATIONS;
|
||||
import static com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants.CAR_FUEL_PERMISSION;
|
||||
import static com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants.CAR_MILEAGE_PERMISSION;
|
||||
import static com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants.CAR_SPEED_PERMISSION;
|
||||
import static com.aldo.apps.familyhelpers.utils.GlobalConstants.SIGN_IN_PROVIDERS;
|
||||
|
||||
@@ -41,6 +43,9 @@ public class HelperGridActivity extends AppCompatActivity {
|
||||
*/
|
||||
private static final String TAG = "HelperGridActivity";
|
||||
|
||||
/**
|
||||
* The {@link LocationHelper} class to share and get location updates.
|
||||
*/
|
||||
private LocationHelper mLocationHelper;
|
||||
|
||||
/**
|
||||
@@ -170,6 +175,12 @@ public class HelperGridActivity extends AppCompatActivity {
|
||||
if (!requestVehicleSpeedPermission()) {
|
||||
Log.d(TAG, "launchHelper: Permission not granted cannot read vehicle speed.");
|
||||
}
|
||||
if (!requestVehicleFuelPermission()) {
|
||||
Log.d(TAG, "launchHelper: Permission not granted, cannot read fuel");
|
||||
}
|
||||
if (!requestVehicleMileagePermission()) {
|
||||
Log.d(TAG, "launchHelper: Permission not granted, cannot read mileage");
|
||||
}
|
||||
if (mLocationHelper.requestLocationPermissions(HelperGridActivity.this)
|
||||
&& mLocationHelper.requestBackgroundLocationPermission(HelperGridActivity.this)) {
|
||||
Log.d(TAG, "launchHelper: Permission already granted");
|
||||
@@ -238,7 +249,7 @@ public class HelperGridActivity extends AppCompatActivity {
|
||||
/**
|
||||
* Helper method to request the VehicleSpeed permission before launching the ShareLocationActivity.
|
||||
*
|
||||
* @return true if granted, flase otherwise.
|
||||
* @return true if granted, false otherwise.
|
||||
*/
|
||||
private boolean requestVehicleSpeedPermission() {
|
||||
if (ContextCompat.checkSelfPermission(this, CAR_SPEED_PERMISSION) ==
|
||||
@@ -255,6 +266,46 @@ public class HelperGridActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to request the VehicleFuel permission before launching the ShareLocationActivity.
|
||||
*
|
||||
* @return true if granted, false otherwise.
|
||||
*/
|
||||
private boolean requestVehicleFuelPermission() {
|
||||
if (ContextCompat.checkSelfPermission(this, CAR_FUEL_PERMISSION) ==
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
// Permission already granted
|
||||
return true;
|
||||
} else {
|
||||
if (shouldShowRequestPermissionRationale(CAR_FUEL_PERMISSION)) {
|
||||
Toast.makeText(HelperGridActivity.this, "Consider granting this for the vehicle info to be readable",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
mRequestPermissionLauncher.launch(CAR_FUEL_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to request the VehicleMileage permission before launching the ShareLocationActivity.
|
||||
*
|
||||
* @return true if granted, false otherwise.
|
||||
*/
|
||||
private boolean requestVehicleMileagePermission() {
|
||||
if (ContextCompat.checkSelfPermission(this, CAR_MILEAGE_PERMISSION) ==
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
// Permission already granted
|
||||
return true;
|
||||
} else {
|
||||
if (shouldShowRequestPermissionRationale(CAR_MILEAGE_PERMISSION)) {
|
||||
Toast.makeText(HelperGridActivity.this, "Consider granting this for the vehicle info to be readable",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
mRequestPermissionLauncher.launch(CAR_MILEAGE_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to request the CameraPermission as it is required to access the
|
||||
* flashlight settings.
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.Screen;
|
||||
import androidx.car.app.annotations.ExperimentalCarApi;
|
||||
@@ -19,9 +20,11 @@ import androidx.lifecycle.LifecycleEventObserver;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
import com.aldo.apps.familyhelpers.auto.model.VehicleInformationHelper;
|
||||
import com.aldo.apps.familyhelpers.auto.screencontent.CarInfoTab;
|
||||
import com.aldo.apps.familyhelpers.auto.screencontent.IScreenContentChangedListener;
|
||||
import com.aldo.apps.familyhelpers.auto.screencontent.ShareLocationTab;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.CarInfoCallbackRepository;
|
||||
|
||||
/**
|
||||
* The {@link AndroidAutoLandingPage} to be shown as a starting point for Android Auto.
|
||||
@@ -50,32 +53,50 @@ public class AndroidAutoLandingPage extends Screen
|
||||
private String mCurrentlySelectedTabId = TAB_KEY_LOCATION;
|
||||
|
||||
/**
|
||||
* C'Tor.
|
||||
*
|
||||
* @param carContext The {@link CarContext} this was instantiated in.
|
||||
* {@link VehicleInformationHelper} to read vehicle information in AA use case.
|
||||
*/
|
||||
protected AndroidAutoLandingPage(@NonNull CarContext carContext) {
|
||||
super(carContext);
|
||||
Log.d(TAG, "AndroidAutoLandingPage() called with: carContext = [" + carContext + "]");
|
||||
getLifecycle().addObserver(mLifecycleObserver);
|
||||
mShareLocationTab = new ShareLocationTab(carContext, this);
|
||||
mCarInfoTab = new CarInfoTab(carContext, this);
|
||||
}
|
||||
private final VehicleInformationHelper mVehicleInformationHelper;
|
||||
|
||||
/**
|
||||
* {@link LifecycleObserver} to stop listening to CarInformation updates when AA ends.
|
||||
* The {@link CarInfoCallbackRepository} to hold all registered callbacks.
|
||||
*/
|
||||
private LifecycleObserver mLifecycleObserver = new LifecycleEventObserver() {
|
||||
private final CarInfoCallbackRepository mCallbackRepo = new CarInfoCallbackRepository();
|
||||
|
||||
/**
|
||||
* {@link LifecycleObserver} to stop listening to Vehicle Speed updates when AA ends.
|
||||
*/
|
||||
private final LifecycleObserver mLifecycleObserver = new LifecycleEventObserver() {
|
||||
@OptIn(markerClass = ExperimentalCarApi.class)
|
||||
@Override
|
||||
public void onStateChanged(@NonNull final LifecycleOwner lifecycleOwner,
|
||||
@NonNull final Lifecycle.Event event) {
|
||||
|
||||
if (event == Lifecycle.Event.ON_STOP) {
|
||||
Log.d(TAG, "onStateChanged: Activity stopped, unsubscribe");
|
||||
mVehicleInformationHelper.unsubscribeFromAllCarInfo();
|
||||
} else if (event == Lifecycle.Event.ON_RESUME) {
|
||||
Log.d(TAG, "onStateChanged: Activity resumed, subscribing");
|
||||
mVehicleInformationHelper.subscribeToAllCarInfo(getCarContext());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* C'Tor.
|
||||
*
|
||||
* @param carContext The {@link CarContext} this was instantiated in.
|
||||
*/
|
||||
@OptIn(markerClass = ExperimentalCarApi.class)
|
||||
protected AndroidAutoLandingPage(@NonNull CarContext carContext) {
|
||||
super(carContext);
|
||||
Log.d(TAG, "AndroidAutoLandingPage() called with: carContext = [" + carContext + "]");
|
||||
getLifecycle().addObserver(mLifecycleObserver);
|
||||
mShareLocationTab = new ShareLocationTab(carContext, this);
|
||||
mVehicleInformationHelper = new VehicleInformationHelper(carContext, mCallbackRepo);
|
||||
mCarInfoTab = new CarInfoTab(carContext, this, mCallbackRepo);
|
||||
getLifecycle().addObserver(mLifecycleObserver);
|
||||
}
|
||||
|
||||
@ExperimentalCarApi
|
||||
@NonNull
|
||||
@Override
|
||||
@@ -111,10 +132,14 @@ public class AndroidAutoLandingPage extends Screen
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@OptIn(markerClass = ExperimentalCarApi.class)
|
||||
@Override
|
||||
public void onScreenContentChanged(final String contentId) {
|
||||
if (TextUtils.equals(contentId, mCurrentlySelectedTabId)) {
|
||||
Log.d(TAG, "onScreenContentChanged: Current screen [" + contentId + "] changed");
|
||||
if (TAB_KEY_CAR_INFO.equals(contentId)) {
|
||||
mCarInfoTab.refreshTemplate();
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model;
|
||||
|
||||
/**
|
||||
* Enum representing the type of CarProperty value.
|
||||
*/
|
||||
public enum CarPropertyType {
|
||||
|
||||
/**
|
||||
* {@link androidx.car.app.hardware.common.CarValue} holds a float value.
|
||||
*/
|
||||
FLOAT,
|
||||
|
||||
/**
|
||||
* {@link androidx.car.app.hardware.common.CarValue} holds an int value.
|
||||
*/
|
||||
INT,
|
||||
|
||||
/**
|
||||
* {@link androidx.car.app.hardware.common.CarValue} holds a String value.
|
||||
*/
|
||||
STRING,
|
||||
|
||||
/**
|
||||
* {@link androidx.car.app.hardware.common.CarValue} holds a boolean value.
|
||||
*/
|
||||
BOOL;
|
||||
}
|
||||
@@ -1,18 +1,55 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model;
|
||||
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.BATTERY_PERCENTAGE;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.CONNECTOR_TYPE;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.DISPLAY_SPEED;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.EV_CONNECTOR_OPEN;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.EV_CONNECTOR_STATE;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.FUEL_PERCENTAGE;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.FUEL_TYPE;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.LOW_ENERGY;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.MANUFACTURER;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.MILEAGE;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.NAME;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.RANGE_REMAINING;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.RAW_SPEED;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.TOLL_CARD;
|
||||
import static com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo.YEAR;
|
||||
import static com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants.CAR_FUEL_PERMISSION;
|
||||
import static com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants.CAR_MILEAGE_PERMISSION;
|
||||
import static com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants.CAR_SPEED_PERMISSION;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.annotations.ExperimentalCarApi;
|
||||
import androidx.car.app.hardware.CarHardwareManager;
|
||||
import androidx.car.app.hardware.common.OnCarDataAvailableListener;
|
||||
import androidx.car.app.hardware.info.CarInfo;
|
||||
import androidx.car.app.hardware.info.EnergyLevel;
|
||||
import androidx.car.app.hardware.info.EnergyProfile;
|
||||
import androidx.car.app.hardware.info.EvStatus;
|
||||
import androidx.car.app.hardware.info.Mileage;
|
||||
import androidx.car.app.hardware.info.Model;
|
||||
import androidx.car.app.hardware.info.Speed;
|
||||
import androidx.car.app.hardware.info.TollCard;
|
||||
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.AbstractCarInfo;
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.CarInfoEnergyLevel;
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.CarInfoEnergyProfile;
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.CarInfoEvStatus;
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.CarInfoMileage;
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.CarInfoModel;
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.CarInfoSpeed;
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.CarInfoTollCard;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.CarInfoCallbackRepository;
|
||||
import com.aldo.apps.familyhelpers.workers.LocationHelper;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Helper class to retrieve a set of {@link CarInfo} to be used in other functionalities.
|
||||
*/
|
||||
@@ -33,12 +70,91 @@ public class VehicleInformationHelper {
|
||||
*/
|
||||
private LocationHelper mLocationHelper;
|
||||
|
||||
/**
|
||||
* {@link WeakReference} to the calling {@link CarContext}.
|
||||
*/
|
||||
private final WeakReference<CarContext> mContextRef;
|
||||
|
||||
/**
|
||||
* The {@link AbstractCarInfo} implementation for the {@link Speed} value.
|
||||
*/
|
||||
private final AbstractCarInfo<Speed> mSpeedValue = new CarInfoSpeed();
|
||||
|
||||
/**
|
||||
* The {@link AbstractCarInfo} implementation for the {@link TollCard} value.
|
||||
*/
|
||||
private final AbstractCarInfo<TollCard> mTollCardValue = new CarInfoTollCard();
|
||||
|
||||
/**
|
||||
* The {@link AbstractCarInfo} implementation for the {@link EnergyLevel} value.
|
||||
*/
|
||||
private final AbstractCarInfo<EnergyLevel> mEnergyLevel = new CarInfoEnergyLevel();
|
||||
|
||||
/**
|
||||
* The {@link AbstractCarInfo} implementation for the {@link EvStatus} value.
|
||||
*/
|
||||
private final AbstractCarInfo<EvStatus> mEvStatus = new CarInfoEvStatus();
|
||||
|
||||
/**
|
||||
* The {@link AbstractCarInfo} implementation for the {@link Mileage} value.
|
||||
*/
|
||||
private final AbstractCarInfo<Mileage> mMileage = new CarInfoMileage();
|
||||
|
||||
/**
|
||||
* The {@link AbstractCarInfo} implementation for the {@link Model} value.
|
||||
*/
|
||||
private final AbstractCarInfo<Model> mModel = new CarInfoModel();
|
||||
|
||||
/**
|
||||
* The {@link AbstractCarInfo} implementation for the {@link EnergyProfile} value.
|
||||
*/
|
||||
private final AbstractCarInfo<EnergyProfile> mEnergyProfile = new CarInfoEnergyProfile();
|
||||
|
||||
private final CarInfoCallbackRepository mCallbacks;
|
||||
|
||||
/**
|
||||
* The {@link OnCarDataAvailableListener} to be invoked when the {@link Speed} value changed
|
||||
*/
|
||||
private final OnCarDataAvailableListener<Speed> mSpeedListener = this::handleReceivedSpeed;
|
||||
|
||||
/**
|
||||
* The {@link OnCarDataAvailableListener} to be invoked when the {@link EnergyProfile} value changed
|
||||
*/
|
||||
private final OnCarDataAvailableListener<EnergyProfile> mEnergyProfileListener = this::handleEnergyProfile;
|
||||
|
||||
/**
|
||||
* The {@link OnCarDataAvailableListener} to be invoked when the {@link Model} value changed
|
||||
*/
|
||||
private final OnCarDataAvailableListener<Model> mModelListener = this::handleModel;
|
||||
|
||||
/**
|
||||
* The {@link OnCarDataAvailableListener} to be invoked when the {@link EnergyLevel} value changed
|
||||
*/
|
||||
private final OnCarDataAvailableListener<EnergyLevel> mEnergyLevelListener = this::handleReceivedEnergyLevel;
|
||||
|
||||
/**
|
||||
* The {@link OnCarDataAvailableListener} to be invoked when the {@link EvStatus} value changed
|
||||
*/
|
||||
private final OnCarDataAvailableListener<EvStatus> mEvStatusListener = this::handleReceivedEvStatus;
|
||||
|
||||
/**
|
||||
* The {@link OnCarDataAvailableListener} to be invoked when the {@link Mileage} value changed
|
||||
*/
|
||||
private final OnCarDataAvailableListener<Mileage> mMileageListener = this::handleReceivedMileage;
|
||||
|
||||
/**
|
||||
* The {@link OnCarDataAvailableListener} to be invoked when the {@link TollCard} value changed
|
||||
*/
|
||||
private final OnCarDataAvailableListener<TollCard> mTollCardListener = this::handleReceivedTollInformation;
|
||||
|
||||
/**
|
||||
* C'Tor.
|
||||
*
|
||||
* @param carContext The {@link CarContext} from which this was instantiated.
|
||||
*/
|
||||
public VehicleInformationHelper(final CarContext carContext) {
|
||||
public VehicleInformationHelper(final CarContext carContext, final CarInfoCallbackRepository callbacks) {
|
||||
mContextRef = new WeakReference<>(carContext);
|
||||
mCallbacks = callbacks;
|
||||
if (carContext.checkCallingOrSelfPermission(CAR_SPEED_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.w(TAG, "VehicleInformationHelper: Nothing to do, permission not granted");
|
||||
return;
|
||||
@@ -47,36 +163,199 @@ public class VehicleInformationHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the Vehicle Speed and handle it.
|
||||
*
|
||||
* @param carContext The {@link CarContext} from which this was called.
|
||||
* Helper method to subscribe to all available {@link CarInfo} values.
|
||||
* @param carContext
|
||||
*/
|
||||
public void subscribeToSpeedValues(final CarContext carContext) {
|
||||
if (carContext.checkCallingOrSelfPermission(CAR_SPEED_PERMISSION) == PackageManager.PERMISSION_GRANTED) {
|
||||
mCarInfo = carContext.getCarService(CarHardwareManager.class).getCarInfo();
|
||||
if (mCarInfo == null) {
|
||||
Log.e(TAG, "subscribeToSpeedValues: No car info available");
|
||||
return;
|
||||
}
|
||||
mCarInfo.addSpeedListener(carContext.getMainExecutor(), this::handleReceivedSpeed);
|
||||
} else {
|
||||
Log.w(TAG, "subscribeToSpeedValues: No Speed permission granted, cannot subscribe");
|
||||
@OptIn(markerClass = ExperimentalCarApi.class)
|
||||
public void subscribeToAllCarInfo(final CarContext carContext) {
|
||||
mCarInfo = carContext.getCarService(CarHardwareManager.class).getCarInfo();
|
||||
if (mCarInfo == null) {
|
||||
Log.d(TAG, "subscribeToAllCarInfo: No CarInfo available, return...");
|
||||
return;
|
||||
}
|
||||
mCarInfo.addTollListener(carContext.getMainExecutor(), mTollCardListener);
|
||||
if (carContext.checkCallingOrSelfPermission(CAR_SPEED_PERMISSION) == PackageManager.PERMISSION_GRANTED) {
|
||||
mCarInfo.addSpeedListener(carContext.getMainExecutor(), mSpeedListener);
|
||||
} else {
|
||||
Log.d(TAG, "subscribeToAllCarInfo: No speed updates as permission not granted");
|
||||
}
|
||||
if (carContext.checkCallingOrSelfPermission(CAR_FUEL_PERMISSION) == PackageManager.PERMISSION_GRANTED) {
|
||||
mCarInfo.addEnergyLevelListener(carContext.getMainExecutor(), mEnergyLevelListener);
|
||||
} else {
|
||||
Log.d(TAG, "subscribeToAllCarInfo: No fuel updates as permission is not granted.");
|
||||
}
|
||||
mCarInfo.addEvStatusListener(carContext.getMainExecutor(), mEvStatusListener);
|
||||
if (carContext.checkCallingOrSelfPermission(CAR_MILEAGE_PERMISSION) == PackageManager.PERMISSION_GRANTED) {
|
||||
mCarInfo.addMileageListener(carContext.getMainExecutor(), mMileageListener);
|
||||
} else {
|
||||
Log.d(TAG, "subscribeToAllCarInfo: No mileage updates as permission is not granted");
|
||||
}
|
||||
mCarInfo.fetchModel(carContext.getMainExecutor(), mModelListener);
|
||||
mCarInfo.fetchEnergyProfile(carContext.getMainExecutor(), mEnergyProfileListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* When AA ends, unsubscribe from the speed value again.
|
||||
* Helper method to unsubscribe from all {@link CarInfo} values, when activity stops.
|
||||
*/
|
||||
public void unsubscribeFromSpeedValue() {
|
||||
mCarInfo.removeSpeedListener(this::handleReceivedSpeed);
|
||||
@ExperimentalCarApi
|
||||
public void unsubscribeFromAllCarInfo() {
|
||||
Log.d(TAG, "unsubscribeFromAllCarInfo: Unsubscribing");
|
||||
mCarInfo.removeTollListener(mTollCardListener);
|
||||
mCarInfo.removeSpeedListener(mSpeedListener);
|
||||
mCarInfo.removeEnergyLevelListener(mEnergyLevelListener);
|
||||
mCarInfo.removeMileageListener(mMileageListener);
|
||||
mCarInfo.removeEvStatusListener(mEvStatusListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the received speed value by publishing it to the {@link LocationHelper}.
|
||||
* Handle the received {@link Speed} value and publish it to the {@link LocationHelper}.
|
||||
*
|
||||
* @param data The {@link Speed} data.
|
||||
* @param speed The {@link Speed} data.
|
||||
*/
|
||||
private void handleReceivedSpeed(@NonNull final Speed data) {
|
||||
mLocationHelper.updateVehicleSpeed(data.getDisplaySpeedMetersPerSecond());
|
||||
private void handleReceivedSpeed(@NonNull final Speed speed) {
|
||||
Log.d(TAG, "handleReceivedSpeed() called with: speed = [" + speed + "]");
|
||||
final CarContext carContext = mContextRef.get();
|
||||
if (carContext == null) {
|
||||
Log.w(TAG, "handleReceivedSpeed: CarContext died, cannot continue.");
|
||||
return;
|
||||
}
|
||||
if (mSpeedValue.hasValueChanged(speed, DISPLAY_SPEED)) {
|
||||
mCallbacks.onMessageChanged(DISPLAY_SPEED, mSpeedValue.getMessageForValue(carContext, speed, DISPLAY_SPEED));
|
||||
mLocationHelper.updateVehicleSpeed(speed.getDisplaySpeedMetersPerSecond());
|
||||
}
|
||||
if (mSpeedValue.hasValueChanged(speed, RAW_SPEED)) {
|
||||
mCallbacks.onMessageChanged(RAW_SPEED, mSpeedValue.getMessageForValue(carContext, speed, RAW_SPEED));
|
||||
}
|
||||
mSpeedValue.setValue(speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the received {@link TollCard} value.
|
||||
*
|
||||
* @param tollCard The {@link TollCard} data.
|
||||
*/
|
||||
private void handleReceivedTollInformation(@NonNull final TollCard tollCard) {
|
||||
Log.d(TAG, "handleReceivedTollInformation() called with: tollCard = [" + tollCard + "]");
|
||||
final CarContext carContext = mContextRef.get();
|
||||
if (carContext == null) {
|
||||
Log.w(TAG, "handleReceivedTollInformation: CarContext died, cannot continue.");
|
||||
return;
|
||||
}
|
||||
if (mTollCardValue.hasValueChanged(tollCard, TOLL_CARD)) {
|
||||
mCallbacks.onMessageChanged(TOLL_CARD, mTollCardValue.getMessageForValue(carContext, tollCard, TOLL_CARD));
|
||||
}
|
||||
mTollCardValue.setValue(tollCard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the received {@link EnergyLevel} value.
|
||||
*
|
||||
* @param energyLevel The {@link EnergyLevel} data.
|
||||
*/
|
||||
@OptIn(markerClass = ExperimentalCarApi.class)
|
||||
private void handleReceivedEnergyLevel(@NonNull final EnergyLevel energyLevel) {
|
||||
Log.d(TAG, "handleReceivedEnergyLevel() called with: energyLevel = [" + energyLevel + "]");
|
||||
final CarContext carContext = mContextRef.get();
|
||||
if (carContext == null) {
|
||||
Log.w(TAG, "handleReceivedEnergyLevel: CarContext died, cannot continue.");
|
||||
return;
|
||||
}
|
||||
if (mEnergyLevel.hasValueChanged(energyLevel, BATTERY_PERCENTAGE)) {
|
||||
mCallbacks.onMessageChanged(BATTERY_PERCENTAGE, mEnergyLevel.getMessageForValue(carContext, energyLevel, BATTERY_PERCENTAGE));
|
||||
}
|
||||
if (mEnergyLevel.hasValueChanged(energyLevel, FUEL_PERCENTAGE)) {
|
||||
mCallbacks.onMessageChanged(FUEL_PERCENTAGE, mEnergyLevel.getMessageForValue(carContext, energyLevel, FUEL_PERCENTAGE));
|
||||
}
|
||||
if (mEnergyLevel.hasValueChanged(energyLevel, LOW_ENERGY)) {
|
||||
mCallbacks.onMessageChanged(LOW_ENERGY, mEnergyLevel.getMessageForValue(carContext, energyLevel, LOW_ENERGY));
|
||||
}
|
||||
if (mEnergyLevel.hasValueChanged(energyLevel, RANGE_REMAINING)) {
|
||||
mCallbacks.onMessageChanged(RANGE_REMAINING, mEnergyLevel.getMessageForValue(carContext, energyLevel, RANGE_REMAINING));
|
||||
}
|
||||
mEnergyLevel.setValue(energyLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the received {@link EvStatus} value.
|
||||
*
|
||||
* @param evStatus The {@link EvStatus} data.
|
||||
*/
|
||||
private void handleReceivedEvStatus(@NonNull final EvStatus evStatus) {
|
||||
Log.d(TAG, "handleReceivedEvStatus() called with: evStatus = [" + evStatus + "]");
|
||||
final CarContext carContext = mContextRef.get();
|
||||
if (carContext == null) {
|
||||
Log.w(TAG, "handleReceivedEvStatus: CarContext died, cannot continue.");
|
||||
return;
|
||||
}
|
||||
if (mEvStatus.hasValueChanged(evStatus, EV_CONNECTOR_OPEN)) {
|
||||
mCallbacks.onMessageChanged(EV_CONNECTOR_OPEN, mEvStatus.getMessageForValue(carContext, evStatus, EV_CONNECTOR_OPEN));
|
||||
}
|
||||
if (mEvStatus.hasValueChanged(evStatus, EV_CONNECTOR_STATE)) {
|
||||
mCallbacks.onMessageChanged(EV_CONNECTOR_STATE, mEvStatus.getMessageForValue(carContext, evStatus, EV_CONNECTOR_STATE));
|
||||
}
|
||||
mEvStatus.setValue(evStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the received {@link Mileage} value.
|
||||
*
|
||||
* @param mileage The {@link Mileage} data.
|
||||
*/
|
||||
private void handleReceivedMileage(@NonNull Mileage mileage) {
|
||||
Log.d(TAG, "handleReceivedMileage() called with: mileage = [" + mileage + "]");
|
||||
final CarContext carContext = mContextRef.get();
|
||||
if (carContext == null) {
|
||||
Log.w(TAG, "handleReceivedMileage: CarContext died, cannot continue.");
|
||||
return;
|
||||
}
|
||||
if (mMileage.hasValueChanged(mileage, MILEAGE)) {
|
||||
mCallbacks.onMessageChanged(MILEAGE, mMileage.getMessageForValue(carContext, mileage, MILEAGE));
|
||||
}
|
||||
mMileage.setValue(mileage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the received {@link Model} value.
|
||||
*
|
||||
* @param model The {@link Model} data.
|
||||
*/
|
||||
private void handleModel(@NonNull Model model) {
|
||||
Log.d(TAG, "handleModel() called with: model = [" + model + "]");
|
||||
final CarContext carContext = mContextRef.get();
|
||||
if (carContext == null) {
|
||||
Log.w(TAG, "handleModel: CarContext died, cannot continue.");
|
||||
return;
|
||||
}
|
||||
if (mModel.hasValueChanged(model, MANUFACTURER)) {
|
||||
mCallbacks.onMessageChanged(MANUFACTURER, mModel.getMessageForValue(carContext, model, MANUFACTURER));
|
||||
}
|
||||
if (mModel.hasValueChanged(model, NAME)) {
|
||||
mCallbacks.onMessageChanged(NAME, mModel.getMessageForValue(carContext, model, NAME));
|
||||
}
|
||||
if (mModel.hasValueChanged(model, YEAR)) {
|
||||
mCallbacks.onMessageChanged(YEAR, mModel.getMessageForValue(carContext, model, YEAR));
|
||||
}
|
||||
mModel.setValue(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the received {@link EnergyProfile} value.
|
||||
*
|
||||
* @param energyProfile The {@link EnergyProfile} data.
|
||||
*/
|
||||
private void handleEnergyProfile(@NonNull final EnergyProfile energyProfile) {
|
||||
Log.d(TAG, "handleEnergyProfile() called with: energyProfile = [" + energyProfile + "]");
|
||||
final CarContext carContext = mContextRef.get();
|
||||
if (carContext == null) {
|
||||
Log.w(TAG, "handleEnergyProfile: CarContext died, cannot continue.");
|
||||
return;
|
||||
}
|
||||
if (mEnergyProfile.hasValueChanged(energyProfile, CONNECTOR_TYPE)) {
|
||||
mCallbacks.onMessageChanged(CONNECTOR_TYPE, mEnergyProfile.getMessageForValue(carContext, energyProfile, CONNECTOR_TYPE));
|
||||
}
|
||||
if (mEnergyProfile.hasValueChanged(energyProfile, FUEL_TYPE)) {
|
||||
mCallbacks.onMessageChanged(FUEL_TYPE, mEnergyProfile.getMessageForValue(carContext, energyProfile, FUEL_TYPE));
|
||||
}
|
||||
mEnergyProfile.setValue(energyProfile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.hardware.common.CarValue;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.model.CarPropertyType;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the CarInfo value holder to prevent boilerplate code.
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class AbstractCarInfo<T> {
|
||||
|
||||
/**
|
||||
* Tag for debugging purpose.
|
||||
*/
|
||||
private static final String TAG = "AbstractCarInfo";
|
||||
|
||||
/**
|
||||
* The received {@link T} value.
|
||||
*/
|
||||
private T mValue;
|
||||
|
||||
/**
|
||||
* Standard empty C'tor.
|
||||
*/
|
||||
protected AbstractCarInfo() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actual value as received from the sensor.
|
||||
*
|
||||
* @param value The {@link T} value.
|
||||
*/
|
||||
public void setValue(final T value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the to be displayed {@link String} for the {@link T} value.
|
||||
*
|
||||
* @param carContext The requesting {@link CarContext}.
|
||||
* @param value The to be handled {@link T} value.
|
||||
* @param carInfo The {@link SupportedCarInfo} to identify which message to generate.
|
||||
*
|
||||
* @return The string to be displayed to the user.
|
||||
*/
|
||||
public String getMessageForValue(final CarContext carContext,
|
||||
final T value,
|
||||
final SupportedCarInfo carInfo) {
|
||||
if (carContext == null) {
|
||||
Log.w(TAG, "getCarManufacturerMessage: Unavailable context, return empty");
|
||||
return "";
|
||||
}
|
||||
if (value == null) {
|
||||
return carContext.getString(R.string.android_auto_car_info_not_received);
|
||||
}
|
||||
switch (getPropertyStatus(value, carInfo)) {
|
||||
case CarValue.STATUS_SUCCESS:
|
||||
return createMessage(carContext, value, carInfo);
|
||||
case CarValue.STATUS_UNIMPLEMENTED:
|
||||
return carContext.getString(R.string.android_auto_car_info_unimplemented);
|
||||
case CarValue.STATUS_UNAVAILABLE:
|
||||
return carContext.getString(R.string.android_auto_car_info_unavailable);
|
||||
case CarValue.STATUS_UNKNOWN:
|
||||
default:
|
||||
return carContext.getString(R.string.android_auto_car_info_unknown);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check whether the message has changed.
|
||||
*
|
||||
* @param carContext The calling {@link CarContext}.
|
||||
* @param newData The received {@link T} data.
|
||||
* @param carInfo The {@link SupportedCarInfo} to identify which message to generate.
|
||||
*
|
||||
* @return true if data has changed, false otherwise.
|
||||
*/
|
||||
public boolean hasMessageChanged(final CarContext carContext,
|
||||
final T newData,
|
||||
final SupportedCarInfo carInfo) {
|
||||
return TextUtils.equals(getMessageForValue(carContext, newData, carInfo),
|
||||
getMessageForValue(carContext, mValue, carInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check whether a specific value has changed (not only the message).
|
||||
*
|
||||
* @param value The received {@link T} data.
|
||||
* @param carInfo The {@link SupportedCarInfo} to identify which value to check.
|
||||
*
|
||||
* @return true if value has changed, false otherwise.
|
||||
*/
|
||||
public boolean hasValueChanged(final T value, final SupportedCarInfo carInfo) {
|
||||
final CarPropertyType propType = carInfo.getPropType();
|
||||
switch (propType) {
|
||||
case FLOAT:
|
||||
return getFloatValue(value, carInfo) == getFloatValue(mValue, carInfo);
|
||||
case INT:
|
||||
return getIntValue(value, carInfo) == getIntValue(mValue, carInfo);
|
||||
case STRING:
|
||||
return TextUtils.equals(getStringValue(value, carInfo), getStringValue(mValue, carInfo));
|
||||
case BOOL:
|
||||
return getBooleanValue(value, carInfo) == getBooleanValue(mValue, carInfo);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create the actual message to be shown for the {@link SupportedCarInfo} of
|
||||
* {@link T} in case of {@link CarValue#STATUS_SUCCESS}.
|
||||
*
|
||||
* @param carContext The calling {@link CarContext}.
|
||||
* @param newData The received {@link T} data.
|
||||
* @param carInfo The {@link SupportedCarInfo} to identify which message to generate.
|
||||
*
|
||||
* @return The generated String message.
|
||||
*/
|
||||
/*package-private*/ abstract String createMessage(final CarContext carContext,
|
||||
final T newData,
|
||||
final SupportedCarInfo carInfo);
|
||||
|
||||
/**
|
||||
* Helper method to the {@link CarValue} status of the specified {@link SupportedCarInfo} of
|
||||
* {@link T}.
|
||||
*
|
||||
* @param newData The received {@link T} data.
|
||||
* @param carInfo The {@link SupportedCarInfo} to identify which status to check.
|
||||
*
|
||||
* @return Either of {@link CarValue#STATUS_SUCCESS}, {@link CarValue#STATUS_UNAVAILABLE},
|
||||
* {@link CarValue#STATUS_UNIMPLEMENTED} or {@link CarValue#STATUS_UNKNOWN}.
|
||||
*/
|
||||
/*package-private*/ abstract int getPropertyStatus(final T newData,
|
||||
final SupportedCarInfo carInfo);
|
||||
|
||||
/**
|
||||
* Helper method to get an integer value of the specified {@link SupportedCarInfo} of
|
||||
* {@link T}.
|
||||
*
|
||||
* @param value The received {@link T} data.
|
||||
* @param propType The {@link SupportedCarInfo} to identify which status to check.
|
||||
*
|
||||
* @return The unwrapped integer value.
|
||||
*/
|
||||
/*package-private*/int getIntValue(final T value, final SupportedCarInfo propType) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get a float value of the specified {@link SupportedCarInfo} of
|
||||
* {@link T}.
|
||||
*
|
||||
* @param value The received {@link T} data.
|
||||
* @param propType The {@link SupportedCarInfo} to identify which status to check.
|
||||
*
|
||||
* @return The unwrapped float value.
|
||||
*/
|
||||
/*package-private*/float getFloatValue(final T value, final SupportedCarInfo propType) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get a String value of the specified {@link SupportedCarInfo} of
|
||||
* {@link T}.
|
||||
*
|
||||
* @param value The received {@link T} data.
|
||||
* @param propType The {@link SupportedCarInfo} to identify which status to check.
|
||||
*
|
||||
* @return The unwrapped String value.
|
||||
*/
|
||||
/*package-private*/ String getStringValue(final T value, final SupportedCarInfo propType) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get a boolean value of the specified {@link SupportedCarInfo} of
|
||||
* {@link T}.
|
||||
*
|
||||
* @param value The received {@link T} data.
|
||||
* @param propType The {@link SupportedCarInfo} to identify which status to check.
|
||||
*
|
||||
* @return The unwrapped boolean value.
|
||||
*/
|
||||
/*package-private*/ boolean getBooleanValue(final T value, final SupportedCarInfo propType) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import static androidx.car.app.hardware.common.CarValue.STATUS_UNKNOWN;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.hardware.info.EnergyLevel;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants;
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the operations needed for the {@link EnergyLevel}.
|
||||
*/
|
||||
public class CarInfoEnergyLevel extends AbstractCarInfo<EnergyLevel>{
|
||||
|
||||
/**
|
||||
* Tag for debugging purpose.
|
||||
*/
|
||||
private static final String TAG = "CarInfoEnergyLevel";
|
||||
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
@Override
|
||||
String createMessage(final CarContext carContext, final EnergyLevel newData, final SupportedCarInfo carInfo) {
|
||||
switch (carInfo) {
|
||||
case BATTERY_PERCENTAGE:
|
||||
return String.format(carContext.getString(R.string.android_auto_energy_level_battery_percentage_base),
|
||||
getFloatValue(newData, SupportedCarInfo.BATTERY_PERCENTAGE));
|
||||
case FUEL_PERCENTAGE:
|
||||
return String.format(carContext.getString(R.string.android_auto_energy_level_fuel_percentage_base),
|
||||
getFloatValue(newData, SupportedCarInfo.FUEL_PERCENTAGE));
|
||||
case LOW_ENERGY:
|
||||
if (getBooleanValue(newData, SupportedCarInfo.LOW_ENERGY)) {
|
||||
return carContext.getString(R.string.android_auto_energy_level_low_energy_true);
|
||||
}
|
||||
return carContext.getString(R.string.android_auto_energy_level_low_energy_false);
|
||||
case RANGE_REMAINING:
|
||||
final int displayUnit = AndroidAutoConstants.getDisplayDistanceUnit(
|
||||
newData.getDistanceDisplayUnit());
|
||||
return String.format(carContext.getString(R.string.android_auto_energy_level_range_remaining_base),
|
||||
AndroidAutoConstants.getTransformedDistanceValue(
|
||||
getFloatValue(newData, SupportedCarInfo.RANGE_REMAINING), displayUnit),
|
||||
AndroidAutoConstants.getDisplayUnitString(carContext, displayUnit));
|
||||
}
|
||||
Log.d(TAG, "createMessage: Unavailable property [" + carInfo + "]");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getPropertyStatus(final EnergyLevel newData, final SupportedCarInfo carInfo) {
|
||||
switch (carInfo) {
|
||||
case BATTERY_PERCENTAGE:
|
||||
return newData.getBatteryPercent().getStatus();
|
||||
case FUEL_PERCENTAGE:
|
||||
return newData.getFuelPercent().getStatus();
|
||||
case LOW_ENERGY:
|
||||
return newData.getEnergyIsLow().getStatus();
|
||||
case RANGE_REMAINING:
|
||||
return newData.getRangeRemainingMeters().getStatus();
|
||||
}
|
||||
Log.d(TAG, "getPropertyStatus: Unavailable property [" + carInfo + "]");
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
float getFloatValue(final EnergyLevel value, final SupportedCarInfo propType) {
|
||||
switch (propType) {
|
||||
case BATTERY_PERCENTAGE:
|
||||
return AndroidAutoConstants.unwrapFloatValue(value.getBatteryPercent());
|
||||
case FUEL_PERCENTAGE:
|
||||
return AndroidAutoConstants.unwrapFloatValue(value.getFuelPercent());
|
||||
case YEAR:case RANGE_REMAINING:
|
||||
return AndroidAutoConstants.unwrapFloatValue(value.getRangeRemainingMeters());
|
||||
}
|
||||
Log.w(TAG, "getFloatValue: Unavailable property [" + propType + "]");
|
||||
return super.getFloatValue(value, propType);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean getBooleanValue(final EnergyLevel value, final SupportedCarInfo propType) {
|
||||
switch (propType) {
|
||||
case LOW_ENERGY:
|
||||
return AndroidAutoConstants.unwrapBooleanValue(value.getEnergyIsLow());
|
||||
}
|
||||
Log.w(TAG, "getBooleanValue: Unavailable property [" + propType + "]");
|
||||
return super.getBooleanValue(value, propType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import static androidx.car.app.hardware.common.CarValue.STATUS_UNKNOWN;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.hardware.info.EnergyProfile;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the operations needed for the {@link EnergyProfile}.
|
||||
*/
|
||||
public class CarInfoEnergyProfile extends AbstractCarInfo<EnergyProfile> {
|
||||
|
||||
/**
|
||||
* Tag for debugging profile
|
||||
*/
|
||||
private static final String TAG = "CarInfoEnergyProfile";
|
||||
|
||||
@Override
|
||||
String createMessage(final CarContext carContext, final EnergyProfile newData, final SupportedCarInfo carInfo) {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
switch (carInfo) {
|
||||
case FUEL_TYPE:
|
||||
final List<Integer> fuelTypes = newData.getFuelTypes().getValue();
|
||||
if (fuelTypes == null || fuelTypes.isEmpty()) {
|
||||
return carContext.getString(R.string.android_auto_car_info_unavailable);
|
||||
}
|
||||
for (final int fuelType : fuelTypes) {
|
||||
stringBuilder.append(AndroidAutoConstants.getFuelTypeString(carContext, fuelType));
|
||||
stringBuilder.append(", ");
|
||||
}
|
||||
return String.format(carContext.getString(R.string.android_auto_energy_profile_fuel_type_base),
|
||||
stringBuilder.toString());
|
||||
case CONNECTOR_TYPE:
|
||||
final List<Integer> connectorTypes = newData.getEvConnectorTypes().getValue();
|
||||
if (connectorTypes == null || connectorTypes.isEmpty()) {
|
||||
return carContext.getString(R.string.android_auto_car_info_unavailable);
|
||||
}
|
||||
for (final int connectorType : connectorTypes) {
|
||||
stringBuilder.append(AndroidAutoConstants.getEvConnectorTypeString(carContext, connectorType));
|
||||
stringBuilder.append(", ");
|
||||
}
|
||||
return String.format(carContext.getString(R.string.android_auto_energy_profile_connector_type_base),
|
||||
stringBuilder.toString());
|
||||
}
|
||||
Log.d(TAG, "createMessage: Unavailable property [" + carInfo + "]");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getPropertyStatus(final EnergyProfile newData, final SupportedCarInfo carInfo) {
|
||||
switch (carInfo) {
|
||||
case FUEL_TYPE:
|
||||
return newData.getFuelTypes().getStatus();
|
||||
case CONNECTOR_TYPE:
|
||||
return newData.getEvConnectorTypes().getStatus();
|
||||
}
|
||||
Log.d(TAG, "getPropertyStatus: Unavailable property [" + carInfo + "]");
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import static androidx.car.app.hardware.common.CarValue.STATUS_UNKNOWN;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.annotations.ExperimentalCarApi;
|
||||
import androidx.car.app.hardware.info.EvStatus;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants;
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the operations needed for the {@link EvStatus}.
|
||||
*/
|
||||
public class CarInfoEvStatus extends AbstractCarInfo<EvStatus> {
|
||||
|
||||
/**
|
||||
* Tag fo debugging purpose.
|
||||
*/
|
||||
private static final String TAG = "CarInfoEvStatus";
|
||||
|
||||
@Override
|
||||
String createMessage(final CarContext carContext, final EvStatus newData, final SupportedCarInfo carInfo) {
|
||||
switch (carInfo) {
|
||||
case EV_CONNECTOR_STATE:
|
||||
if(getBooleanValue(newData, SupportedCarInfo.EV_CONNECTOR_STATE)) {
|
||||
return carContext.getString(R.string.android_auto_ev_status_charge_port_connected_true);
|
||||
}
|
||||
return carContext.getString(R.string.android_auto_ev_status_charge_port_connected_false);
|
||||
case EV_CONNECTOR_OPEN:
|
||||
if(getBooleanValue(newData, SupportedCarInfo.EV_CONNECTOR_OPEN)) {
|
||||
return carContext.getString(R.string.android_auto_ev_status_charge_port_connected_true);
|
||||
}
|
||||
return carContext.getString(R.string.android_auto_ev_status_charge_port_connected_false);
|
||||
}
|
||||
Log.d(TAG, "createMessage: Unavailable property [" + carInfo + "]");
|
||||
return null;
|
||||
}
|
||||
|
||||
@OptIn(markerClass = ExperimentalCarApi.class)
|
||||
@Override
|
||||
int getPropertyStatus(final EvStatus newData, final SupportedCarInfo carInfo) {
|
||||
switch (carInfo) {
|
||||
case EV_CONNECTOR_STATE:
|
||||
return newData.getEvChargePortConnected().getStatus();
|
||||
case EV_CONNECTOR_OPEN:
|
||||
return newData.getEvChargePortOpen().getStatus();
|
||||
}
|
||||
Log.d(TAG, "getPropertyStatus: Unavailable property [" + carInfo + "]");
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
@OptIn(markerClass = ExperimentalCarApi.class)
|
||||
@Override
|
||||
boolean getBooleanValue(final EvStatus value, final SupportedCarInfo propType) {
|
||||
switch (propType) {
|
||||
case EV_CONNECTOR_STATE:
|
||||
return AndroidAutoConstants.unwrapBooleanValue(value.getEvChargePortConnected());
|
||||
case EV_CONNECTOR_OPEN:
|
||||
return AndroidAutoConstants.unwrapBooleanValue(value.getEvChargePortOpen());
|
||||
}
|
||||
Log.w(TAG, "getBooleanValue: Unavailable property [" + propType + "]");
|
||||
return super.getBooleanValue(value, propType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import static androidx.car.app.hardware.common.CarValue.STATUS_UNKNOWN;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.hardware.info.Mileage;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants;
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the operations needed for the {@link Mileage}.
|
||||
*/
|
||||
public class CarInfoMileage extends AbstractCarInfo<Mileage> {
|
||||
|
||||
/**
|
||||
* Tag for debugging purpose.
|
||||
*/
|
||||
private static final String TAG = "CarInfoMileage";
|
||||
|
||||
@Override
|
||||
String createMessage(final CarContext carContext, final Mileage newData, final SupportedCarInfo carInfo) {
|
||||
if (carInfo == SupportedCarInfo.MILEAGE) {
|
||||
final int targetUnit = AndroidAutoConstants.getDisplayDistanceUnit(
|
||||
newData.getDistanceDisplayUnit());
|
||||
return String.format(carContext.getString(R.string.android_auto_ev_mileage_odometer_base),
|
||||
AndroidAutoConstants.getTransformedDistanceValue(
|
||||
getFloatValue(newData, SupportedCarInfo.MILEAGE), targetUnit),
|
||||
AndroidAutoConstants.getDisplayUnitString(carContext, targetUnit));
|
||||
}
|
||||
Log.d(TAG, "createMessage: Unavailable property [" + carInfo + "]");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getPropertyStatus(final Mileage newData, final SupportedCarInfo carInfo) {
|
||||
if (carInfo == SupportedCarInfo.MILEAGE) {
|
||||
newData.getOdometerMeters().getStatus();
|
||||
}
|
||||
Log.d(TAG, "getPropertyStatus: Unavailable property [" + carInfo + "]");
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
float getFloatValue(final Mileage value, final SupportedCarInfo propType) {
|
||||
if (propType == SupportedCarInfo.MILEAGE) {
|
||||
return AndroidAutoConstants.unwrapFloatValue(value.getOdometerMeters());
|
||||
}
|
||||
Log.w(TAG, "getFloatValue: Unavailable property [" + propType + "]");
|
||||
return super.getFloatValue(value, propType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import static androidx.car.app.hardware.common.CarValue.STATUS_UNKNOWN;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.hardware.info.Model;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants;
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the operations needed for the {@link Model}.
|
||||
*/
|
||||
public class CarInfoModel extends AbstractCarInfo<Model> {
|
||||
|
||||
/**
|
||||
* Tag for debugging purpose.
|
||||
*/
|
||||
private static final String TAG = "CarInfoModel";
|
||||
|
||||
/**
|
||||
* Empty C'Tor.
|
||||
*/
|
||||
public CarInfoModel() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
String createMessage(final CarContext carContext,final Model newData, final SupportedCarInfo carInfo) {
|
||||
switch (carInfo) {
|
||||
case MANUFACTURER:
|
||||
return String.format(carContext.getString(R.string.android_auto_model_manufacturer_base),
|
||||
getStringValue(newData, carInfo));
|
||||
case NAME:
|
||||
return String.format(carContext.getString(R.string.android_auto_model_name_base),
|
||||
getStringValue(newData, carInfo));
|
||||
case YEAR:
|
||||
return String.format(carContext.getString(R.string.android_auto_model_year_base),
|
||||
getIntValue(newData, carInfo));
|
||||
}
|
||||
Log.d(TAG, "createMessage: Unavailable property [" + carInfo + "]");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getPropertyStatus(final Model newData, final SupportedCarInfo carInfo) {
|
||||
switch (carInfo) {
|
||||
case MANUFACTURER:
|
||||
return newData.getManufacturer().getStatus();
|
||||
case NAME:
|
||||
return newData.getName().getStatus();
|
||||
case YEAR:
|
||||
return newData.getYear().getStatus();
|
||||
}
|
||||
Log.d(TAG, "getPropertyStatus: Unavailable property [" + carInfo + "]");
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getIntValue(final Model value, final SupportedCarInfo propType) {
|
||||
switch (propType) {
|
||||
case YEAR:
|
||||
return AndroidAutoConstants.unwrapIntValue(value.getYear());
|
||||
}
|
||||
Log.w(TAG, "getIntValue: Unavailable property [" + propType + "]");
|
||||
return super.getIntValue(value, propType);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getStringValue(final Model value, final SupportedCarInfo propType) {
|
||||
switch (propType) {
|
||||
case MANUFACTURER:
|
||||
return value.getManufacturer().getValue();
|
||||
case NAME:
|
||||
return value.getName().getValue();
|
||||
}
|
||||
Log.w(TAG, "getStringValue: Unavailable property [" + propType + "]");
|
||||
return super.getStringValue(value, propType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import static androidx.car.app.hardware.common.CarValue.STATUS_UNKNOWN;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.hardware.info.Speed;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants;
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the operations needed for the {@link Speed}.
|
||||
*/
|
||||
public class CarInfoSpeed extends AbstractCarInfo<Speed> {
|
||||
|
||||
/**
|
||||
* Tag for debugging purposes.
|
||||
*/
|
||||
private static final String TAG = "CarInfoSpeed";
|
||||
|
||||
@Override
|
||||
String createMessage(final CarContext carContext, final Speed newData, final SupportedCarInfo carInfo) {
|
||||
final int targetUnit = AndroidAutoConstants.getDisplaySpeedUnit(
|
||||
newData.getSpeedDisplayUnit());
|
||||
switch (carInfo) {
|
||||
case RAW_SPEED:
|
||||
return String.format(carContext.getString(R.string.android_auto_raw_speed_base_string),
|
||||
AndroidAutoConstants.getTransformedSpeedValue(
|
||||
getFloatValue(newData, SupportedCarInfo.RAW_SPEED), targetUnit),
|
||||
AndroidAutoConstants.getDisplaySpeedUnitString(carContext, targetUnit));
|
||||
case DISPLAY_SPEED:
|
||||
return String.format(carContext.getString(R.string.android_auto_display_speed_base_string),
|
||||
AndroidAutoConstants.getTransformedSpeedValue(
|
||||
getFloatValue(newData, SupportedCarInfo.DISPLAY_SPEED), targetUnit),
|
||||
AndroidAutoConstants.getDisplaySpeedUnitString(carContext, targetUnit));
|
||||
}
|
||||
Log.d(TAG, "createMessage: Unavailable property [" + carInfo + "]");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getPropertyStatus(final Speed newData, final SupportedCarInfo carInfo) {
|
||||
switch (carInfo) {
|
||||
case RAW_SPEED:
|
||||
newData.getRawSpeedMetersPerSecond().getStatus();
|
||||
case DISPLAY_SPEED:
|
||||
newData.getDisplaySpeedMetersPerSecond().getStatus();
|
||||
}
|
||||
Log.d(TAG, "getPropertyStatus: Unavailable property [" + carInfo + "]");
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
float getFloatValue(final Speed value, final SupportedCarInfo propType) {
|
||||
switch (propType) {
|
||||
case RAW_SPEED:
|
||||
return AndroidAutoConstants.unwrapFloatValue(value.getRawSpeedMetersPerSecond());
|
||||
case DISPLAY_SPEED:
|
||||
return AndroidAutoConstants.unwrapFloatValue(value.getDisplaySpeedMetersPerSecond());
|
||||
}
|
||||
Log.w(TAG, "getFloatValue: Unavailable property [" + propType + "]");
|
||||
return super.getFloatValue(value, propType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import static androidx.car.app.hardware.common.CarValue.STATUS_UNKNOWN;
|
||||
import static androidx.car.app.hardware.info.TollCard.TOLLCARD_STATE_INVALID;
|
||||
import static androidx.car.app.hardware.info.TollCard.TOLLCARD_STATE_NOT_INSERTED;
|
||||
import static androidx.car.app.hardware.info.TollCard.TOLLCARD_STATE_UNKNOWN;
|
||||
import static androidx.car.app.hardware.info.TollCard.TOLLCARD_STATE_VALID;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.hardware.info.TollCard;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants;
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the operations needed for the {@link TollCard}.
|
||||
*/
|
||||
public class CarInfoTollCard extends AbstractCarInfo<TollCard> {
|
||||
|
||||
/**
|
||||
* Tag for debugging purpose.
|
||||
*/
|
||||
private static final String TAG = "CarInfoTollCard";
|
||||
|
||||
@Override
|
||||
String createMessage(final CarContext carContext, final TollCard newData, final SupportedCarInfo carInfo) {
|
||||
if (carInfo == SupportedCarInfo.TOLL_CARD) {
|
||||
return String.format(carContext.getString(R.string.android_auto_toll_card_state_base),
|
||||
getTollCardStateString(carContext, getIntValue(newData, SupportedCarInfo.TOLL_CARD)));
|
||||
}
|
||||
Log.d(TAG, "createMessage: Unavailable property [" + carInfo + "]");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getPropertyStatus(final TollCard newData, final SupportedCarInfo carInfo) {
|
||||
if (carInfo == SupportedCarInfo.TOLL_CARD) {
|
||||
return newData.getCardState().getStatus();
|
||||
}
|
||||
Log.d(TAG, "getPropertyStatus: Unavailable property [" + carInfo + "]");
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getIntValue(final TollCard value, final SupportedCarInfo propType) {
|
||||
if (propType == SupportedCarInfo.TOLL_CARD) {
|
||||
return AndroidAutoConstants.unwrapIntValue(value.getCardState());
|
||||
}
|
||||
Log.w(TAG, "getIntValue: Unavailable property [" + propType + "]");
|
||||
return super.getIntValue(value, propType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to unbox the displayUnit.
|
||||
*
|
||||
* @param carContext The requesting {@link CarContext}.
|
||||
* @param tollCardState The {@link TollCard} state representation.
|
||||
*
|
||||
* @return The {@link String} representing the {@link TollCard} state, defaults to
|
||||
* {@link TollCard#TOLLCARD_STATE_UNKNOWN}.
|
||||
*/
|
||||
private String getTollCardStateString(final CarContext carContext, final int tollCardState) {
|
||||
switch (tollCardState) {
|
||||
case TOLLCARD_STATE_INVALID:
|
||||
return carContext.getString(R.string.android_auto_toll_card_state_invalid);
|
||||
case TOLLCARD_STATE_VALID:
|
||||
return carContext.getString(R.string.android_auto_toll_card_state_valid);
|
||||
case TOLLCARD_STATE_NOT_INSERTED:
|
||||
return carContext.getString(R.string.android_auto_toll_card_state_not_inserted);
|
||||
case TOLLCARD_STATE_UNKNOWN:
|
||||
default:
|
||||
return carContext.getString(R.string.android_auto_toll_card_state_unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.aldo.apps.familyhelpers.auto.model.carinfo;
|
||||
|
||||
import com.aldo.apps.familyhelpers.auto.model.CarPropertyType;
|
||||
|
||||
/**
|
||||
* Enum class representing the potentially available {@link androidx.car.app.hardware.info.CarInfo}s.
|
||||
*/
|
||||
public enum SupportedCarInfo {
|
||||
/**
|
||||
* The raw speed as reported by the car.
|
||||
*/
|
||||
RAW_SPEED(0, CarPropertyType.FLOAT),
|
||||
|
||||
/**
|
||||
* The display speed as reported by the car.
|
||||
*/
|
||||
DISPLAY_SPEED(1, CarPropertyType.FLOAT),
|
||||
|
||||
/**
|
||||
* The toll card status as reported by the car.
|
||||
*/
|
||||
TOLL_CARD(2, CarPropertyType.INT),
|
||||
|
||||
/**
|
||||
* The current charge percentage of the battery.
|
||||
*/
|
||||
BATTERY_PERCENTAGE(3, CarPropertyType.FLOAT),
|
||||
|
||||
/**
|
||||
* The current fuel percentage.
|
||||
*/
|
||||
FUEL_PERCENTAGE(4, CarPropertyType.FLOAT),
|
||||
|
||||
/**
|
||||
* The remaining range.
|
||||
*/
|
||||
RANGE_REMAINING(5, CarPropertyType.FLOAT),
|
||||
|
||||
/**
|
||||
* The flag indicating whether the Car is on lowEnergy or not.
|
||||
*/
|
||||
LOW_ENERGY(6, CarPropertyType.BOOL),
|
||||
|
||||
/**
|
||||
* The flag indicating whether the EV connector port is open or not.
|
||||
*/
|
||||
EV_CONNECTOR_OPEN(7, CarPropertyType.BOOL),
|
||||
|
||||
/**
|
||||
* The flag indicating whether the EV connector port is connected or not.
|
||||
*/
|
||||
EV_CONNECTOR_STATE(8, CarPropertyType.BOOL),
|
||||
|
||||
/**
|
||||
* The flag indicating whether the EV connector port is open or not.
|
||||
*/
|
||||
MILEAGE(9, CarPropertyType.FLOAT),
|
||||
|
||||
/**
|
||||
* The name of the cars manufacturer.
|
||||
*/
|
||||
MANUFACTURER(10, CarPropertyType.STRING),
|
||||
|
||||
/**
|
||||
* The name of the car model.
|
||||
*/
|
||||
NAME(11, CarPropertyType.STRING),
|
||||
|
||||
/**
|
||||
* The construction year.
|
||||
*/
|
||||
YEAR(12, CarPropertyType.INT),
|
||||
|
||||
/**
|
||||
* The list of supported fuel types.
|
||||
*/
|
||||
FUEL_TYPE(13, CarPropertyType.INT),
|
||||
|
||||
/**
|
||||
* The list of supported ev connector ports.
|
||||
*/
|
||||
CONNECTOR_TYPE(14, CarPropertyType.INT);
|
||||
|
||||
/**
|
||||
* The index of the item in the UI.
|
||||
*/
|
||||
private final int mIndex;
|
||||
|
||||
/**
|
||||
* The {@link CarPropertyType} to determine the value to be retrieved.
|
||||
*/
|
||||
private final CarPropertyType mPropType;
|
||||
|
||||
/**
|
||||
* C'Tor.
|
||||
*
|
||||
* @param index The index of the item in the UI.
|
||||
* @param propType The {@link CarPropertyType} to determine the value to be retrieved.
|
||||
*/
|
||||
SupportedCarInfo(final int index, final CarPropertyType propType) {
|
||||
mIndex = index;
|
||||
mPropType = propType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the item in the UI.
|
||||
*
|
||||
* @return The index of the item in the UI.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link CarPropertyType} to determine the value to be retrieved.
|
||||
*
|
||||
* @return The {@link CarPropertyType} to determine the value to be retrieved.
|
||||
*/
|
||||
public CarPropertyType getPropType() {
|
||||
return mPropType;
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public abstract class AbstractTabContent {
|
||||
* @param listener The {@link IScreenContentChangedListener} to be invoked if page content changed.
|
||||
*/
|
||||
protected AbstractTabContent(final CarContext carContext,
|
||||
final IScreenContentChangedListener listener) {
|
||||
final IScreenContentChangedListener listener) {
|
||||
mContextRef = new WeakReference<>(carContext);
|
||||
mScreenContentChangedListener = listener;
|
||||
}
|
||||
|
||||
@@ -2,17 +2,29 @@ package com.aldo.apps.familyhelpers.auto.screencontent;
|
||||
|
||||
import static com.aldo.apps.familyhelpers.auto.utils.AndroidAutoConstants.TAB_KEY_CAR_INFO;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.CarToast;
|
||||
import androidx.car.app.annotations.ExperimentalCarApi;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.ListTemplate;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.Tab;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.model.Toggle;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
import com.aldo.apps.familyhelpers.auto.model.VehicleInformationHelper;
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo;
|
||||
import com.aldo.apps.familyhelpers.auto.utils.CarInfoCallbackRepository;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* The {@link Tab} to be shown for the CarInfo.
|
||||
*/
|
||||
public class CarInfoTab extends AbstractTabContent {
|
||||
|
||||
/**
|
||||
@@ -20,25 +32,52 @@ public class CarInfoTab extends AbstractTabContent {
|
||||
*/
|
||||
private static final String TAG = "CarInfoTab";
|
||||
|
||||
/**
|
||||
* {@link VehicleInformationHelper} to read vehicle information in AA use case.
|
||||
*/
|
||||
private final VehicleInformationHelper mVehicleInformationHelper;
|
||||
|
||||
/**
|
||||
* The {@link Template} for the car info tab.
|
||||
*/
|
||||
private Template mCarInfoTab;
|
||||
|
||||
/**
|
||||
* {@link CarInfoCallbackRepository} holding all registered callbacks.
|
||||
*/
|
||||
private final CarInfoCallbackRepository mCallbacks;
|
||||
|
||||
/**
|
||||
* The {@link IScreenContentChangedListener} to be invoked if the page content changed.
|
||||
*/
|
||||
private IScreenContentChangedListener mContentChangeListener;
|
||||
|
||||
/**
|
||||
* The {@link Map} holding a mapping of {@link SupportedCarInfo} and the {@link Disposable}
|
||||
* subscription in order to cancel ongoing subscriptions.
|
||||
*/
|
||||
private final Map<SupportedCarInfo, Disposable> mSubscriptionMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The {@link Map} holding the last received message for each {@link SupportedCarInfo} to be
|
||||
* read from.
|
||||
*/
|
||||
private final Map<SupportedCarInfo, String> mMessageMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The currently selected {@link SupportedCarInfo} item.
|
||||
*/
|
||||
private SupportedCarInfo mCurrentlySelectedItem = SupportedCarInfo.RAW_SPEED;
|
||||
|
||||
/**
|
||||
* C'Tor.
|
||||
*
|
||||
* @param carContext Calling {@link CarContext}.
|
||||
* @param listener The {@link IScreenContentChangedListener} to be invoked if page content changed.
|
||||
* @param callbacks The {@link CarInfoCallbackRepository} holding all registered callbacks.
|
||||
*/
|
||||
public CarInfoTab(final CarContext carContext, final IScreenContentChangedListener listener) {
|
||||
@ExperimentalCarApi
|
||||
public CarInfoTab(final CarContext carContext,
|
||||
final IScreenContentChangedListener listener,
|
||||
final CarInfoCallbackRepository callbacks) {
|
||||
super(carContext, listener);
|
||||
mVehicleInformationHelper = new VehicleInformationHelper(carContext);
|
||||
mCallbacks = callbacks;
|
||||
mContentChangeListener = listener;
|
||||
refreshTemplate();
|
||||
}
|
||||
|
||||
@@ -57,16 +96,133 @@ public class CarInfoTab extends AbstractTabContent {
|
||||
}
|
||||
|
||||
@Override
|
||||
@ExperimentalCarApi
|
||||
public void refreshTemplate() {
|
||||
final Row vehicleInfo = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_vehicle_info_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_car_info), Row.IMAGE_TYPE_ICON)
|
||||
.setOnClickListener(this::startCarInfoScreen)
|
||||
final Row rawSpeed = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_raw_speed_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_speed), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.RAW_SPEED, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.RAW_SPEED))
|
||||
.build();
|
||||
|
||||
final Row displaySpeed = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_display_speed_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_speed), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.DISPLAY_SPEED, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.DISPLAY_SPEED))
|
||||
.build();
|
||||
|
||||
final Row tollCard = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_toll_card_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_toll_card), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.TOLL_CARD, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.TOLL_CARD))
|
||||
.build();
|
||||
|
||||
final Row batPerc = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_energy_level_battery_percentage_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_battery_percentage), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.BATTERY_PERCENTAGE, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.BATTERY_PERCENTAGE))
|
||||
.build();
|
||||
|
||||
final Row fuelPerc = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_energy_level_fuel_percentage_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_fuel_percentage), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.FUEL_PERCENTAGE, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.FUEL_PERCENTAGE))
|
||||
.build();
|
||||
|
||||
final Row lowEnergy = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_energy_level_low_energy_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_low_energy), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.LOW_ENERGY, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.LOW_ENERGY))
|
||||
.build();
|
||||
|
||||
final Row rangeRemaining = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_energy_level_range_remaining_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_range_remaining), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.RANGE_REMAINING, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.RANGE_REMAINING))
|
||||
.build();
|
||||
|
||||
final Row evConnectorOpen = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_ev_status_charge_port_open_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_ev_connector), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.EV_CONNECTOR_OPEN, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.EV_CONNECTOR_OPEN))
|
||||
.build();
|
||||
|
||||
final Row evConnectorState = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_ev_status_charge_port_connected_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_ev_connector), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.EV_CONNECTOR_STATE, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.EV_CONNECTOR_STATE))
|
||||
.build();
|
||||
|
||||
final Row mileage = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_mileage_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_mileage), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.MILEAGE, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.MILEAGE))
|
||||
.build();
|
||||
|
||||
final Row manufacturer = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_model_manufacturer_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_car_info), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.MANUFACTURER, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.MANUFACTURER))
|
||||
.build();
|
||||
|
||||
final Row name = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_model_name_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_car_info), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.NAME, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.NAME))
|
||||
.build();
|
||||
|
||||
final Row year = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_model_year_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_car_info), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.YEAR, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.YEAR))
|
||||
.build();
|
||||
|
||||
final Row fuelType = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_energy_profile_fuel_type_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_fuel_percentage), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.FUEL_TYPE, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.FUEL_TYPE))
|
||||
.build();
|
||||
|
||||
final Row connectorType = new Row.Builder()
|
||||
.setTitle(getString(R.string.android_auto_energy_profile_connector_type_title))
|
||||
.setImage(getIconForResource(R.drawable.ic_ev_connector), Row.IMAGE_TYPE_ICON)
|
||||
.addText(mMessageMap.getOrDefault(SupportedCarInfo.CONNECTOR_TYPE, ""))
|
||||
.setToggle(createAndAssigneToggle(SupportedCarInfo.CONNECTOR_TYPE))
|
||||
.build();
|
||||
|
||||
Log.d(TAG, "refreshTemplate: selected Item = [" + mCurrentlySelectedItem + "]");
|
||||
|
||||
final ItemList carList = new ItemList.Builder()
|
||||
.setNoItemsMessage(getString(R.string.android_auto_share_location_no_items_yet))
|
||||
.addItem(vehicleInfo)
|
||||
.addItem(rawSpeed)
|
||||
.addItem(displaySpeed)
|
||||
.addItem(tollCard)
|
||||
.addItem(batPerc)
|
||||
.addItem(fuelPerc)
|
||||
.addItem(rangeRemaining)
|
||||
.addItem(lowEnergy)
|
||||
.addItem(evConnectorOpen)
|
||||
.addItem(evConnectorState)
|
||||
.addItem(mileage)
|
||||
.addItem(manufacturer)
|
||||
.addItem(name)
|
||||
.addItem(year)
|
||||
.addItem(fuelType)
|
||||
.addItem(connectorType)
|
||||
.setSelectedIndex(mCurrentlySelectedItem.getIndex())
|
||||
.build();
|
||||
|
||||
mCarInfoTab = new ListTemplate.Builder()
|
||||
@@ -75,9 +231,74 @@ public class CarInfoTab extends AbstractTabContent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to be invoked when a list item is clicked.
|
||||
* Helper method to create and fill a {@link Toggle} to be shown in the UI.
|
||||
*
|
||||
* @param supportedCarInfo The {@link SupportedCarInfo} to be assigned to the topic.
|
||||
*
|
||||
* @return The created {@link Toggle}.
|
||||
*/
|
||||
private void startCarInfoScreen() {
|
||||
CarToast.makeText(getCarContext(), "Not yet implemented", CarToast.LENGTH_LONG).show();
|
||||
private Toggle createAndAssigneToggle(final SupportedCarInfo supportedCarInfo) {
|
||||
return new Toggle.Builder(isChecked -> handleCheckedChanged(isChecked, supportedCarInfo))
|
||||
.setChecked(mSubscriptionMap.containsKey(supportedCarInfo))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to be invoked when the checked state of a toggle changes.
|
||||
*
|
||||
* @param isChecked True if checked, false otherwise.
|
||||
* @param supportedCarInfo The assigned {@link SupportedCarInfo}.
|
||||
*/
|
||||
private void handleCheckedChanged(final boolean isChecked, final SupportedCarInfo supportedCarInfo) {
|
||||
mCurrentlySelectedItem = supportedCarInfo;
|
||||
if (isChecked) {
|
||||
if (mSubscriptionMap.containsKey(supportedCarInfo)) {
|
||||
Log.d(TAG, "handleCheckedChanged: Already subscribed, no need to update");
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "handleCheckedChanged: Subscribing to [" + supportedCarInfo + "]");
|
||||
mSubscriptionMap.put(supportedCarInfo, mCallbacks.getObservableForTopic(supportedCarInfo)
|
||||
.subscribe(message -> handleSubscriptionEvent(supportedCarInfo, message),
|
||||
throwable -> handleSubscriptionError(supportedCarInfo, throwable)));
|
||||
} else {
|
||||
if (mSubscriptionMap.containsKey(supportedCarInfo)) {
|
||||
Log.d(TAG, "handleCheckedChanged: Unsubscribing from [" + supportedCarInfo + "]");
|
||||
final Disposable disposable = mSubscriptionMap.get(supportedCarInfo);
|
||||
if (disposable != null && !disposable.isDisposed()) {
|
||||
disposable.dispose();
|
||||
mSubscriptionMap.remove(supportedCarInfo);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "handleCheckedChanged: Not yet subscribed, no need to update.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to be invoked whenever data is received from the CarService.
|
||||
*
|
||||
* @param supportedCarInfo The {@link SupportedCarInfo} in focus.
|
||||
* @param newMessage The new message received.
|
||||
*/
|
||||
private void handleSubscriptionEvent(final SupportedCarInfo supportedCarInfo, final String newMessage) {
|
||||
Log.d(TAG, "handleSubscriptionEvent() called with: supportedCarInfo = [" + supportedCarInfo
|
||||
+ "], newMessage = [" + newMessage + "]");
|
||||
mMessageMap.put(supportedCarInfo, newMessage);
|
||||
mContentChangeListener.onScreenContentChanged(TAB_KEY_CAR_INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to be invoked if the subscription failed to a specific topic.
|
||||
*
|
||||
* @param supportedCarInfo The {@link SupportedCarInfo}.
|
||||
* @param throwable The {@link Throwable} that occurred.
|
||||
*/
|
||||
private void handleSubscriptionError(final SupportedCarInfo supportedCarInfo, final Throwable throwable) {
|
||||
if (mSubscriptionMap.containsKey(supportedCarInfo)) {
|
||||
mSubscriptionMap.get(supportedCarInfo).dispose();
|
||||
mSubscriptionMap.remove(supportedCarInfo);
|
||||
}
|
||||
Log.e(TAG, "handleSubscriptionError()supportedCarInfo = [" + supportedCarInfo
|
||||
+ "], throwable = [" + throwable + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
package com.aldo.apps.familyhelpers.auto.utils;
|
||||
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_CHADEMO;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_COMBO_1;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_COMBO_2;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_GBT;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_GBT_DC;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_J1772;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_MENNEKES;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_OTHER;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_SCAME;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_TESLA_HPWC;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_TESLA_ROADSTER;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_TESLA_SUPERCHARGER;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.EVCONNECTOR_TYPE_UNKNOWN;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_BIODIESEL;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_CNG;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_DIESEL_1;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_DIESEL_2;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_E85;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_ELECTRIC;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_HYDROGEN;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_LEADED;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_LNG;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_LPG;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_OTHER;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_UNKNOWN;
|
||||
import static androidx.car.app.hardware.info.EnergyProfile.FUEL_TYPE_UNLEADED;
|
||||
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.annotations.ExperimentalCarApi;
|
||||
import androidx.car.app.hardware.common.CarUnit;
|
||||
import androidx.car.app.hardware.common.CarValue;
|
||||
|
||||
import com.aldo.apps.familyhelpers.R;
|
||||
|
||||
/**
|
||||
* Constants class for Android Auto.
|
||||
*/
|
||||
@@ -19,4 +53,360 @@ public class AndroidAutoConstants {
|
||||
* Name of the permission for the VehicleSpeed.
|
||||
*/
|
||||
public static final String CAR_SPEED_PERMISSION = "com.google.android.gms.permission.CAR_SPEED";
|
||||
|
||||
/**
|
||||
* Name of the permission for the VehicleFuel state.
|
||||
*/
|
||||
public static final String CAR_FUEL_PERMISSION = "com.google.android.gms.permission.CAR_FUEL";
|
||||
|
||||
/**
|
||||
* Name of the permission for the VehicleMileage state.
|
||||
*/
|
||||
public static final String CAR_MILEAGE_PERMISSION = "com.google.android.gms.permission.CAR_MILEAGE";
|
||||
|
||||
/**
|
||||
* Modifier to transform received meter per second values to kilometer per hour.
|
||||
*/
|
||||
public static final float MPS_TP_KMH_MODIFICATOR = 3.6f;
|
||||
|
||||
/**
|
||||
* Modifier to transform received meter per second values to miles per hour.
|
||||
*/
|
||||
public static final float MPS_TP_MPH_MODIFICATOR = 2.23694f;
|
||||
|
||||
/**
|
||||
* Modifier to transform received meters into kilometers.
|
||||
*/
|
||||
public static final float METERS_TO_KILOMETERS_MODIFICATOR = 0.001f;
|
||||
|
||||
/**
|
||||
* Modifier to transform received meters into miles.
|
||||
*/
|
||||
public static final float METERS_TO_MILES_MODIFICATOR = 0.00062137119223734f;
|
||||
|
||||
/**
|
||||
* Modifier to transform received liters into US gallons.
|
||||
*/
|
||||
public static final float LITERS_TO_US_GALLON_MODIFICATOR = 0.26417205235815f;
|
||||
|
||||
/**
|
||||
* Modifier to transform received liters into imperial gallons.
|
||||
*/
|
||||
public static final float LITERS_TO_IMPERIAL_GALLON_MODIFIER = 0.219969f;
|
||||
|
||||
/**
|
||||
* Modifier to transform received liters into milliliters.
|
||||
*/
|
||||
public static final float LITERS_TO_MILLILITERS_MODIFIER = 0.0001f;
|
||||
|
||||
|
||||
/**
|
||||
* Transforms the received MeterPerSecond value into the respective value of the given display
|
||||
* unit.
|
||||
|
||||
* @param baseValue The received value.
|
||||
* @param targetUnit The unit to which to transform.
|
||||
*
|
||||
* @return The transformed value.
|
||||
*/
|
||||
public static float getTransformedSpeedValue(final float baseValue, final int targetUnit) {
|
||||
switch (targetUnit) {
|
||||
case CarUnit.METERS_PER_SEC:
|
||||
return baseValue;
|
||||
case CarUnit.MILES_PER_HOUR:
|
||||
return baseValue * MPS_TP_MPH_MODIFICATOR;
|
||||
case CarUnit.KILOMETERS_PER_HOUR:
|
||||
default:
|
||||
return baseValue * MPS_TP_KMH_MODIFICATOR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to unbox the displayUnit.
|
||||
*
|
||||
* @param displayUnitObj The {@link CarValue<Integer>} representing the unit.
|
||||
*
|
||||
* @return The {@link CarUnit} of the displaySpeed, defaults to {@link CarUnit#METERS_PER_SEC}.
|
||||
*/
|
||||
public static int getDisplaySpeedUnit(final CarValue<Integer> displayUnitObj) {
|
||||
if (displayUnitObj == null || displayUnitObj.getStatus() != CarValue.STATUS_SUCCESS) {
|
||||
return CarUnit.METERS_PER_SEC;
|
||||
}
|
||||
return displayUnitObj.getValue() != null ? displayUnitObj.getValue() : CarUnit.METERS_PER_SEC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the proper text representation of the displaySpeedValue.
|
||||
*
|
||||
* @param carContext The calling {@link CarContext}
|
||||
* @param unit The int representation of the target unit.
|
||||
*
|
||||
* @return The string representation of the provided {@link CarUnit}, defaults to
|
||||
* {@link CarUnit#METERS_PER_SEC}.
|
||||
*/
|
||||
public static String getDisplaySpeedUnitString(final CarContext carContext, final int unit) {
|
||||
switch (unit) {
|
||||
case CarUnit.KILOMETERS_PER_HOUR:
|
||||
return carContext.getString(R.string.android_auto_speed_unit_kmh);
|
||||
case CarUnit.MILES_PER_HOUR:
|
||||
return carContext.getString(R.string.android_auto_speed_unit_mph);
|
||||
case CarUnit.METERS_PER_SEC:
|
||||
default:
|
||||
return carContext.getString(R.string.android_auto_speed_unit_mps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the received Meter value into the respective value of the given display
|
||||
* unit.
|
||||
|
||||
* @param baseValue The received value.
|
||||
* @param targetUnit The unit to which to transform.
|
||||
*
|
||||
* @return The transformed value.
|
||||
*/
|
||||
public static float getTransformedDistanceValue(final float baseValue, final int targetUnit) {
|
||||
switch (targetUnit) {
|
||||
case CarUnit.METER:
|
||||
return baseValue;
|
||||
case CarUnit.MILE:
|
||||
return baseValue * METERS_TO_MILES_MODIFICATOR;
|
||||
case CarUnit.KILOMETER:
|
||||
default:
|
||||
return baseValue * METERS_TO_KILOMETERS_MODIFICATOR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to unbox the displayUnit.
|
||||
*
|
||||
* @param displayUnitObj The {@link CarValue<Integer>} representing the unit.
|
||||
*
|
||||
* @return The {@link CarUnit} of the displayDistance, defaults to {@link CarUnit#METER}.
|
||||
*/
|
||||
public static int getDisplayDistanceUnit(final CarValue<Integer> displayUnitObj) {
|
||||
if (displayUnitObj == null || displayUnitObj.getStatus() != CarValue.STATUS_SUCCESS) {
|
||||
return CarUnit.METER;
|
||||
}
|
||||
return displayUnitObj.getValue() != null ? displayUnitObj.getValue() : CarUnit.METER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the proper text representation of the displayDistanceValue.
|
||||
*
|
||||
* @param carContext The calling {@link CarContext}
|
||||
* @param unit The int representation of the target unit.
|
||||
*
|
||||
* @return The string representation of the provided {@link CarUnit}, defaults to
|
||||
* {@link CarUnit#METER}.
|
||||
*/
|
||||
public static String getDisplayUnitString(final CarContext carContext, final int unit) {
|
||||
switch (unit) {
|
||||
case CarUnit.KILOMETER:
|
||||
return carContext.getString(R.string.android_auto_distance_unit_km);
|
||||
case CarUnit.MILE:
|
||||
return carContext.getString(R.string.android_auto_distance_unit_miles);
|
||||
case CarUnit.METER:
|
||||
default:
|
||||
return carContext.getString(R.string.android_auto_distance_unit_meters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Transforms the received volume value into the respective value of the given display
|
||||
* unit.
|
||||
|
||||
* @param baseValue The received value.
|
||||
* @param targetUnit The unit to which to transform.
|
||||
*
|
||||
* @return The transformed value.
|
||||
*/
|
||||
@ExperimentalCarApi
|
||||
public static float getTransformedVolumeValue(final float baseValue, final int targetUnit) {
|
||||
switch (targetUnit) {
|
||||
case CarUnit.US_GALLON:
|
||||
return baseValue * LITERS_TO_US_GALLON_MODIFICATOR;
|
||||
case CarUnit.IMPERIAL_GALLON:
|
||||
return baseValue * LITERS_TO_IMPERIAL_GALLON_MODIFIER;
|
||||
case CarUnit.MILLILITER:
|
||||
return baseValue * LITERS_TO_MILLILITERS_MODIFIER;
|
||||
case CarUnit.LITER:
|
||||
default:
|
||||
return baseValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to unbox the displayUnit.
|
||||
*
|
||||
* @param displayUnitObj The {@link CarValue<Integer>} representing the unit.
|
||||
*
|
||||
* @return The {@link CarUnit} of the displayVolume, defaults to {@link CarUnit#LITER}.
|
||||
*/
|
||||
@ExperimentalCarApi
|
||||
public static int getDisplayVolumeUnit(final CarValue<Integer> displayUnitObj) {
|
||||
if (displayUnitObj == null || displayUnitObj.getStatus() != CarValue.STATUS_SUCCESS) {
|
||||
return CarUnit.LITER;
|
||||
}
|
||||
return displayUnitObj.getValue() != null ? displayUnitObj.getValue() : CarUnit.LITER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the proper text representation of the displayVolumeValue.
|
||||
*
|
||||
* @param carContext The calling {@link CarContext}
|
||||
* @param unit The int representation of the target unit.
|
||||
*
|
||||
* @return The string representation of the provided {@link CarUnit}, defaults to
|
||||
* {@link CarUnit#LITER}.
|
||||
*/
|
||||
@ExperimentalCarApi
|
||||
public static String getDisplayVolumeString(final CarContext carContext, final int unit) {
|
||||
switch (unit) {
|
||||
case CarUnit.US_GALLON:
|
||||
return carContext.getString(R.string.android_auto_volume_unit_us_gallon);
|
||||
case CarUnit.IMPERIAL_GALLON:
|
||||
return carContext.getString(R.string.android_auto_volume_unit_imperial_gallon);
|
||||
case CarUnit.MILLILITER:
|
||||
return carContext.getString(R.string.android_auto_volume_unit_milliliter);
|
||||
case CarUnit.LITER:
|
||||
default:
|
||||
return carContext.getString(R.string.android_auto_volume_unit_liter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to safely unwrap a {@link CarValue} of type {@link Float} to make it a primitive
|
||||
* type.
|
||||
*
|
||||
* @param floatValue The {@link CarValue} of type {@link Float}.
|
||||
*
|
||||
* @return The unwrapped primitive type.
|
||||
*/
|
||||
public static float unwrapFloatValue(final CarValue<Float> floatValue) {
|
||||
final Float actualValue = floatValue.getValue();
|
||||
if (actualValue == null || actualValue.isNaN() || actualValue.isInfinite()) {
|
||||
return 0.0f;
|
||||
}
|
||||
return actualValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to safely unwrap a {@link CarValue} of type {@link Integer} to make it a primitive
|
||||
* type.
|
||||
*
|
||||
* @param intValue The {@link CarValue} of type {@link Integer}.
|
||||
*
|
||||
* @return The unwrapped primitive type.
|
||||
*/
|
||||
public static int unwrapIntValue(final CarValue<Integer> intValue) {
|
||||
final Integer actualValue = intValue.getValue();
|
||||
if (actualValue == null) {
|
||||
return 0;
|
||||
}
|
||||
return actualValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to safely unwrap a {@link CarValue} of type {@link Boolean} to make it a primitive
|
||||
* type.
|
||||
*
|
||||
* @param boolValue The {@link CarValue} of type {@link Boolean}.
|
||||
*
|
||||
* @return The unwrapped primitive type.
|
||||
*/
|
||||
public static boolean unwrapBooleanValue(final CarValue<Boolean> boolValue) {
|
||||
final Boolean actualValue = boolValue.getValue();
|
||||
if (actualValue == null) {
|
||||
return false;
|
||||
}
|
||||
return actualValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the proper text representation of the fuel type.
|
||||
*
|
||||
* @param carContext The calling {@link CarContext}
|
||||
* @param fuelType The int representation of the fuel type.
|
||||
*
|
||||
* @return The string representation of the provided
|
||||
* {@link androidx.car.app.hardware.info.EnergyProfile.FuelType}, defaults to
|
||||
* {@link androidx.car.app.hardware.info.EnergyProfile#FUEL_TYPE_UNKNOWN}.
|
||||
*/
|
||||
public static String getFuelTypeString(final CarContext carContext, final int fuelType ) {
|
||||
switch (fuelType) {
|
||||
case FUEL_TYPE_UNLEADED:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_unleaded);
|
||||
case FUEL_TYPE_LEADED:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_leaded);
|
||||
case FUEL_TYPE_DIESEL_1:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_diesel_1);
|
||||
case FUEL_TYPE_DIESEL_2:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_diesel_2);
|
||||
case FUEL_TYPE_BIODIESEL:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_biodiesel);
|
||||
case FUEL_TYPE_E85:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_e85);
|
||||
case FUEL_TYPE_LPG:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_lpg);
|
||||
case FUEL_TYPE_CNG:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_cng);
|
||||
case FUEL_TYPE_LNG:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_lng);
|
||||
case FUEL_TYPE_ELECTRIC:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_electric);
|
||||
case FUEL_TYPE_HYDROGEN:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_hydrogen);
|
||||
case FUEL_TYPE_OTHER:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_other);
|
||||
case FUEL_TYPE_UNKNOWN:
|
||||
default:
|
||||
return carContext.getString(R.string.android_auto_fuel_type_unknown);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the proper text representation of the connector type.
|
||||
*
|
||||
* @param carContext The calling {@link CarContext}
|
||||
* @param conType The int representation of the connector type.
|
||||
*
|
||||
* @return The string representation of the provided
|
||||
* {@link androidx.car.app.hardware.info.EnergyProfile.EvConnectorType}, defaults to
|
||||
* {@link androidx.car.app.hardware.info.EnergyProfile#EVCONNECTOR_TYPE_UNKNOWN}.
|
||||
*/
|
||||
public static String getEvConnectorTypeString(final CarContext carContext, final int conType) {
|
||||
switch (conType) {
|
||||
case EVCONNECTOR_TYPE_J1772:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_j1772);
|
||||
case EVCONNECTOR_TYPE_MENNEKES:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_mennekes);
|
||||
case EVCONNECTOR_TYPE_CHADEMO:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_chademo);
|
||||
case EVCONNECTOR_TYPE_COMBO_1:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_combo_1);
|
||||
case EVCONNECTOR_TYPE_COMBO_2:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_combo_2);
|
||||
case EVCONNECTOR_TYPE_TESLA_ROADSTER:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_tesla_roadster);
|
||||
case EVCONNECTOR_TYPE_TESLA_HPWC:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_tesla_hpwc);
|
||||
case EVCONNECTOR_TYPE_TESLA_SUPERCHARGER:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_tesla_supercharger);
|
||||
case EVCONNECTOR_TYPE_GBT:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_gbt);
|
||||
case EVCONNECTOR_TYPE_GBT_DC:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_gbt_dc);
|
||||
case EVCONNECTOR_TYPE_SCAME:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_scame);
|
||||
case EVCONNECTOR_TYPE_OTHER:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_other);
|
||||
case EVCONNECTOR_TYPE_UNKNOWN:
|
||||
default:
|
||||
return carContext.getString(R.string.android_auto_ev_connector_unknown);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.aldo.apps.familyhelpers.auto.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.aldo.apps.familyhelpers.auto.model.carinfo.SupportedCarInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||
|
||||
/**
|
||||
* Helper class offering the {@link BehaviorSubject}s for the different supported values and utility
|
||||
* methods to access them.
|
||||
*/
|
||||
public class CarInfoCallbackRepository {
|
||||
|
||||
/**
|
||||
* Tag for debugging purpose.
|
||||
*/
|
||||
private static final String TAG = "CarInfoCallbackRepository";
|
||||
|
||||
/**
|
||||
* The {@link Map} holding a mapping of {@link SupportedCarInfo} to actual {@link BehaviorSubject}.
|
||||
*/
|
||||
private Map<SupportedCarInfo, BehaviorSubject<String>> mObservableMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* C'Tor.
|
||||
*/
|
||||
public CarInfoCallbackRepository() {
|
||||
Log.d(TAG, "CarInfoCallbackRepository: Creating all observables.");
|
||||
for (final SupportedCarInfo supportedCarInfo : SupportedCarInfo.values()) {
|
||||
mObservableMap.put(supportedCarInfo, BehaviorSubject.create());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the to be shown message has changed, will call onNext on the respective
|
||||
* {@link BehaviorSubject}.
|
||||
*
|
||||
* @param supportedCarInfo The {@link SupportedCarInfo} that changed.
|
||||
* @param newMessage The new message to be shown.
|
||||
*/
|
||||
public void onMessageChanged(final SupportedCarInfo supportedCarInfo, final String newMessage) {
|
||||
Log.d(TAG, "onDataChanged() called with: supportedCarInfo = [" + supportedCarInfo
|
||||
+ "], newMessage = [" + newMessage + "]");
|
||||
final BehaviorSubject<String> topicObservable = mObservableMap.get(supportedCarInfo);
|
||||
if (topicObservable == null) {
|
||||
Log.w(TAG, "onDataChanged: No observable, cannot update value for [" + supportedCarInfo + "]");
|
||||
return;
|
||||
}
|
||||
topicObservable.onNext(newMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message observable for the given topic.
|
||||
*
|
||||
* @param carInfo The {@link SupportedCarInfo}.
|
||||
*
|
||||
* @return The message to be shown.
|
||||
*/
|
||||
public BehaviorSubject<String> getObservableForTopic(final SupportedCarInfo carInfo) {
|
||||
final BehaviorSubject<String> topicObservable = mObservableMap.get(carInfo);
|
||||
if (topicObservable == null) {
|
||||
Log.w(TAG, "onDataChanged: No observable, return empty observable for [" + carInfo + "]");
|
||||
return BehaviorSubject.createDefault("");
|
||||
}
|
||||
return topicObservable;
|
||||
}
|
||||
}
|
||||
@@ -103,15 +103,6 @@ public class ActiveShareAdapter extends RecyclerView.Adapter<ActiveShareAdapter.
|
||||
return mCurrentlySelectedSubject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to clear the selected state of all views, when a new one is tapped.
|
||||
*/
|
||||
private void clearFocusedView() {
|
||||
for (final View view : mAllItems) {
|
||||
view.setSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link RecyclerView.ViewHolder} implementation for the {@link ActiveShareViewHolder}.
|
||||
*/
|
||||
@@ -179,5 +170,14 @@ public class ActiveShareAdapter extends RecyclerView.Adapter<ActiveShareAdapter.
|
||||
.placeholder(R.drawable.ic_unknown_user)
|
||||
.into(mProfilePicture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to clear the selected state of all views, when a new one is tapped.
|
||||
*/
|
||||
private void clearFocusedView() {
|
||||
for (final View view : mAllItems) {
|
||||
view.setSelected(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
app/src/main/res/drawable/ic_battery_percentage.xml
Normal file
4
app/src/main/res/drawable/ic_battery_percentage.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<vector android:height="200dp" android:viewportHeight="16"
|
||||
android:viewportWidth="16" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#2e3434" android:pathData="m7,0c-1,0 -1,1 -1,1v1h-1s-0.707,-0.016 -1.445,0.355c-0.742,0.371 -1.555,1.313 -1.555,2.645v8s-0.016,0.707 0.355,1.449c0.371,0.738 1.313,1.551 2.645,1.551h6s0.707,0.016 1.449,-0.355c0.738,-0.371 1.551,-1.313 1.551,-2.645v-8c0,-1.332 -0.813,-2.273 -1.551,-2.645c-0.742,-0.371 -1.449,-0.355 -1.449,-0.355h-1v-1c0,-1 -1,-1 -1,-1zM8,4h3c0.555,0 1,0.445 1,1v8c0,0.555 -0.445,1 -1,1h-6c-0.555,0 -1,-0.445 -1,-1v-8c0,-0.555 0.445,-1 1,-1zM5,7v6h6v-6zM5,7"/>
|
||||
</vector>
|
||||
4
app/src/main/res/drawable/ic_ev_connector.xml
Normal file
4
app/src/main/res/drawable/ic_ev_connector.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<vector android:height="200dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M12,2A10,10 0,1 0,22 12,10 10,0 0,0 12,2ZM12,20a8,8 0,1 1,8 -8A8,8 0,0 1,12 20ZM18,12.75a1.25,1.25 0,1 1,-1.25 -1.25A1.25,1.25 0,0 1,18 12.75ZM13.5,16.5A1.5,1.5 0,1 1,12 15,1.5 1.5,0 0,1 13.5,16.5ZM8.5,12.75A1.25,1.25 0,1 1,7.25 11.5,1.25 1.25,0 0,1 8.5,12.75ZM9.5,10A1.5,1.5 0,1 1,11 8.5,1.5 1.5,0 0,1 9.5,10ZM14.5,10A1.5,1.5 0,1 1,16 8.5,1.5 1.5,0 0,1 14.5,10Z"/>
|
||||
</vector>
|
||||
4
app/src/main/res/drawable/ic_fuel_percentage.xml
Normal file
4
app/src/main/res/drawable/ic_fuel_percentage.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<vector android:height="200dp" android:viewportHeight="15"
|
||||
android:viewportWidth="15" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M13,6L13,6v5.5c0,0.276 -0.224,0.5 -0.5,0.5S12,11.776 12,11.5v-2C12,8.672 11.328,8 10.5,8H9V2c0,-0.552 -0.448,-1 -1,-1H2C1.448,1 1,1.448 1,2v11c0,0.552 0.448,1 1,1h6c0.552,0 1,-0.448 1,-1V9h1.5C10.776,9 11,9.224 11,9.5v2c0,0.828 0.672,1.5 1.5,1.5s1.5,-0.672 1.5,-1.5V5c0,-0.552 -0.448,-1 -1,-1l0,0V2.49C12.995,2.218 12.772,2 12.5,2c-0.282,0.005 -0.506,0.237 -0.502,0.518C11.999,2.529 11.999,2.539 12,2.55V5C12,5.552 12.448,6 13,6s1,-0.448 1,-1s-0.448,-1 -1,-1M8,6.5C8,6.776 7.776,7 7.5,7h-5C2.224,7 2,6.776 2,6.5v-3C2,3.224 2.224,3 2.5,3h5C7.776,3 8,3.224 8,3.5V6.5z"/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_low_energy.xml
Normal file
14
app/src/main/res/drawable/ic_low_energy.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<vector android:height="200dp" android:viewportHeight="25"
|
||||
android:viewportWidth="25" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M18.15,17L3.5,17C3.22,17 3,16.78 3,16.5L3,8.5C3,8.22 3.22,8 3.5,8L18.15,8C18.43,8 18.65,8.22 18.65,8.5L18.65,16.5C18.65,16.78 18.42,17 18.15,17Z"
|
||||
android:strokeColor="#0F0F0F" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="1"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M20.88,10.81L21.5,10.81C21.78,10.81 22,11.03 22,11.31L22,13.69C22,13.97 21.78,14.19 21.5,14.19L20.88,14.19"
|
||||
android:strokeColor="#0F0F0F" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="1"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M5.23,10.25L5.23,14.75"
|
||||
android:strokeColor="#0F0F0F" android:strokeLineCap="round" android:strokeWidth="1"/>
|
||||
</vector>
|
||||
4
app/src/main/res/drawable/ic_mileage.xml
Normal file
4
app/src/main/res/drawable/ic_mileage.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<vector android:height="200dp" android:viewportHeight="501.02"
|
||||
android:viewportWidth="501.02" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M242.1,115.92L242.1,115.92h-0.01V96.01V56.19h0.01h16.8v59.73h-0.02v0.01l-8.39,-0.01H242.1zM39.56,317.1l41.92,-7.39l16.91,-2.98v-0.01h0.01l-1.48,-8.33l-1.44,-8.19h-0.01v-0.01l-58.83,10.37L39.56,317.1zM411.27,169.23l-30.23,17.44v0.01l0,0l4.66,8.09l3.73,6.45l0,0l51.73,-29.86l-8.4,-14.55L411.27,169.23zM150.24,390.92l-6.62,-5.56l0,0l0,0l-38.4,45.75l12.88,10.81l16.71,-19.92l21.69,-25.84l0,0L150.24,390.92zM432.56,386.81l8.39,-14.56l-18.05,-10.42l-33.67,-19.46v0.01l0,0l-4.64,8.03l-3.75,6.51l0,0v0.01L432.56,386.81zM36.7,242.28l20.98,3.69l37.84,6.69v-0.01h0.01l2.5,-14.22l0.41,-2.33v-0.01l-58.83,-10.38L36.7,242.28zM461.04,226.16l-15.99,2.81l-42.84,7.54v0.01h-0.01l2.16,12.26l0.76,4.28l0,0v0.01l58.84,-10.37L461.04,226.16zM189.35,128.1v0.01l13.64,-4.97l2.14,-0.78h0.01l-20.42,-56.14l-15.79,5.76l2.91,8L189.35,128.1L189.35,128.1zM67.81,386.43l51.72,-29.86v-0.01l0,0l-6.47,-11.2l-1.93,-3.35l0,0l0,0l-51.73,29.86l8.4,14.55h0.01V386.43zM343.78,396.43l38.4,45.77L395.04,431.4v-0.01l-38.38,-45.76v0.01v-0.01l-8.93,7.49L343.78,396.43L343.78,396.43zM59.63,170.99L59.63,170.99l51.73,29.88l0,0l7.28,-12.61l1.12,-1.94v-0.01l-51.73,-29.86L59.63,170.99zM463.88,300.97L463.88,300.97l-58.82,-10.38l-0.63,3.55l-2.29,13l58.83,10.38L463.88,300.97zM118.41,101.05l-12.87,10.8l14.11,16.81l24.29,28.95l0,0l0,0l7.6,-6.38l5.26,-4.41l0,0l0.01,-0.01L118.41,101.05zM311.25,80.2L295.85,122.5l0.01,0.01l0,0l10.52,3.82l5.26,1.91l0,0h0.01l20.43,-56.13l-15.79,-5.74L311.25,80.2zM353.71,155.15l3.26,2.73l0,0l0,0l38.4,-45.77l-12.87,-10.79h-0.01l0,0l-38.4,45.75l0,0v0.01L353.71,155.15zM250.51,27.02C112.38,27.02 0,139.39 0,277.53c0,79.57 37.33,150.54 95.36,196.46h25.36C57.04,431.78 14.94,359.49 14.94,277.53c0,-129.9 105.67,-235.57 235.57,-235.57c129.9,0 235.57,105.67 235.57,235.57c0,81.96 -42.1,154.25 -105.79,196.46h25.36c58.02,-45.93 95.36,-116.89 95.36,-196.46C501.02,139.4 388.63,27.02 250.51,27.02zM201.61,387.23c5.26,0 7.88,-5.24 7.88,-15.7c0,-10.83 -2.57,-16.25 -7.71,-16.25c-5.42,0 -8.14,5.5 -8.14,16.52C193.63,382.09 196.29,387.23 201.61,387.23zM179.15,336.71h44.55v69.7h-44.55V336.71zM189.18,372.01c0,6.12 1.05,10.79 3.16,14.03c2.11,3.23 5.05,4.86 8.82,4.86c4.03,0 7.16,-1.7 9.41,-5.08c2.25,-3.4 3.37,-8.3 3.37,-14.73c0,-12.99 -3.98,-19.48 -11.93,-19.48c-4.16,0 -7.33,1.71 -9.53,5.17C190.28,360.21 189.18,365.29 189.18,372.01zM229.56,336.71h43.75v69.7H229.56V336.71zM241.05,389.33c1.74,1.04 4.36,1.57 7.87,1.57c4.17,0 7.46,-1.12 9.85,-3.37s3.59,-5.21 3.59,-8.89c0,-3.55 -1.11,-6.35 -3.33,-8.39c-2.23,-2.03 -5.38,-3.06 -9.44,-3.06c-0.99,0 -2.07,0.04 -3.23,0.11v-11.14h14.29v-3.92h-18.4V371.3c2.92,-0.21 4.91,-0.32 5.96,-0.32c3.14,0 5.54,0.7 7.21,2.09c1.68,1.4 2.52,3.35 2.52,5.83c0,2.52 -0.82,4.53 -2.47,6.05c-1.65,1.52 -3.81,2.28 -6.49,2.28c-2.69,0 -5.33,-0.84 -7.93,-2.52v4.61H241.05zM277.85,336.71h44.01v69.7h-44.01V336.71zM288.79,372.01c0,6.12 1.05,10.79 3.17,14.03c2.11,3.23 5.05,4.86 8.82,4.86c4.03,0 7.17,-1.7 9.41,-5.08c2.25,-3.4 3.37,-8.3 3.37,-14.73c0,-12.99 -3.98,-19.48 -11.94,-19.48c-4.15,0 -7.33,1.71 -9.53,5.17C289.89,360.21 288.79,365.29 288.79,372.01zM301.23,387.23c5.25,0 7.88,-5.24 7.88,-15.7c0,-10.83 -2.57,-16.25 -7.71,-16.25c-5.43,0 -8.14,5.5 -8.14,16.52C293.24,382.09 295.9,387.23 301.23,387.23zM257.82,300.73c-1.05,0 -1.97,0.38 -2.94,0.58L140.06,200.02L242.19,314.97c-0.07,0.58 -0.36,1.1 -0.36,1.67c0,8.85 7.14,16 15.98,16c8.78,0 15.92,-7.15 15.92,-16C273.75,307.88 266.6,300.73 257.82,300.73z"/>
|
||||
</vector>
|
||||
16
app/src/main/res/drawable/ic_range_remaining.xml
Normal file
16
app/src/main/res/drawable/ic_range_remaining.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<vector android:height="200dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M9.11,5.08c0,2.39 -3.81,6 -3.81,6s-3.82,-3.58 -3.82,-6A3.7,3.7 0,0 1,5.3 1.5,3.7 3.7,0 0,1 9.11,5.08Z"
|
||||
android:strokeColor="#020202" android:strokeWidth="1.91"/>
|
||||
<path android:fillColor="#020202" android:pathData="M5.3,5.32m-0.95,0a0.95,0.95 0,1 1,1.9 0a0.95,0.95 0,1 1,-1.9 0"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M4.34,13h4.3A2.39,2.39 0,0 1,11 15.34h0a2.39,2.39 0,0 1,-2.38 2.39H3.86a2.39,2.39 0,0 0,-2.38 2.38h0A2.39,2.39 0,0 0,3.86 22.5H17.7"
|
||||
android:strokeColor="#020202" android:strokeWidth="1.91"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M16.75,9.14L16.75,20.59"
|
||||
android:strokeColor="#020202" android:strokeWidth="1.91"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M16.75,14.86l4.77,0l-0.95,-1.9l0.95,-1.92l-4.77,0l0,3.82z"
|
||||
android:strokeColor="#020202" android:strokeWidth="1.91"/>
|
||||
</vector>
|
||||
30
app/src/main/res/drawable/ic_speed.xml
Normal file
30
app/src/main/res/drawable/ic_speed.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<vector android:height="200dp" android:viewportHeight="48"
|
||||
android:viewportWidth="48" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillAlpha="0.01" android:fillColor="#ffffff" android:pathData="M0,0h48v48h-48z"/>
|
||||
<path android:fillColor="#2F88FF"
|
||||
android:pathData="M30.297,18.779C30.297,18.779 27.068,27.881 25.533,29.47C23.999,31.059 21.466,31.103 19.877,29.569C18.288,28.034 18.244,25.502 19.779,23.913C21.313,22.324 30.297,18.779 30.297,18.779Z"
|
||||
android:strokeColor="#000000" android:strokeLineJoin="round" android:strokeWidth="4"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M38.849,38.849C42.65,35.049 45,29.799 45,24C45,12.402 35.598,3 24,3C12.402,3 3,12.402 3,24C3,29.799 5.351,35.049 9.151,38.849"
|
||||
android:strokeColor="#000000" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="4"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M24,4V8"
|
||||
android:strokeColor="#000000" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="4"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M38.845,11.142L35.737,13.659"
|
||||
android:strokeColor="#000000" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="4"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M42.522,27.233L38.625,26.333"
|
||||
android:strokeColor="#000000" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="4"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M5.477,27.233L9.375,26.333"
|
||||
android:strokeColor="#000000" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="4"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M9.155,11.142L12.263,13.659"
|
||||
android:strokeColor="#000000" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="4"/>
|
||||
</vector>
|
||||
8
app/src/main/res/drawable/ic_toll_card.xml
Normal file
8
app/src/main/res/drawable/ic_toll_card.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<vector android:height="200dp" android:viewportHeight="398.8"
|
||||
android:viewportWidth="398.8" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M295.23,142.7c-9.9,-44.67 -19.8,-89.34 -29.71,-134c-16.72,0 -33.44,0 -50.15,0c2.39,44.67 4.78,89.34 7.17,134H295.23z"/>
|
||||
<path android:fillColor="#000000" android:pathData="M226.35,214c3.14,58.7 6.29,117.4 9.43,176.11c38.09,0 76.19,0 114.28,0c-13.01,-58.7 -26.02,-117.4 -39.03,-176.11H226.35z"/>
|
||||
<path android:fillColor="#000000" android:pathData="M183.43,8.69c-16.72,0 -33.43,0 -50.15,0c-9.9,44.67 -19.8,89.33 -29.7,134h72.68C178.66,98.03 181.04,53.36 183.43,8.69z"/>
|
||||
<path android:fillColor="#000000" android:pathData="M48.74,390.11c38.1,0 76.19,0 114.28,0c3.15,-58.7 6.29,-117.4 9.43,-176.11H87.79C74.78,272.71 61.76,331.41 48.74,390.11z"/>
|
||||
<path android:fillColor="#000000" android:pathData="M394.18,161.21H4.63c-2.56,0 -4.63,2.07 -4.63,4.63v25.02c0,2.56 2.07,4.63 4.63,4.63h25.05v37.48c0,2.56 2.07,4.63 4.63,4.63h25c2.12,0 3.96,-1.44 4.48,-3.49l9.82,-38.62h251.6l9.82,38.62c0.52,2.05 2.37,3.49 4.49,3.49h24.99c2.56,0 4.63,-2.07 4.63,-4.63v-37.48h25.05c2.56,0 4.63,-2.07 4.63,-4.63v-25.02C398.8,163.28 396.73,161.21 394.18,161.21z"/>
|
||||
</vector>
|
||||
@@ -107,4 +107,94 @@
|
||||
<string name="android_auto_tab_name_location">Location</string>
|
||||
<string name="android_auto_tab_name_car_info">CarInfo</string>
|
||||
|
||||
<!--Android Auto - CarInfo generic Strings -->
|
||||
<string name="android_auto_car_info_not_received" translatable="false">Value not yet received</string>
|
||||
<string name="android_auto_car_info_unavailable" translatable="false">Requested value is currently unavailable</string>
|
||||
<string name="android_auto_car_info_unimplemented" translatable="false">Requested value is not implemented</string>
|
||||
<string name="android_auto_car_info_unknown" translatable="false">Requested value state is currently unknown</string>
|
||||
<!--Android Auto - Speed Value Strings -->
|
||||
<string name="android_auto_raw_speed_title" translatable="false">Raw Vehicle Speed</string>
|
||||
<string name="android_auto_display_speed_title" translatable="false">Display Vehicle Speed</string>
|
||||
<string name="android_auto_raw_speed_base_string" translatable="false">Current Raw Speed is %.2f %s</string>
|
||||
<string name="android_auto_display_speed_base_string" translatable="false">Current Display Speed is %.2f %s</string>
|
||||
<string name="android_auto_speed_unit_mps" translatable="false">m/s</string>
|
||||
<string name="android_auto_speed_unit_mph" translatable="false">Mph</string>
|
||||
<string name="android_auto_speed_unit_kmh" translatable="false">km/h</string>
|
||||
<string name="android_auto_distance_unit_meters" translatable="false">m</string>
|
||||
<string name="android_auto_distance_unit_miles" translatable="false">mi</string>
|
||||
<string name="android_auto_distance_unit_km" translatable="false">km</string>
|
||||
<string name="android_auto_volume_unit_liter" translatable="false">l</string>
|
||||
<string name="android_auto_volume_unit_milliliter" translatable="false">ml</string>
|
||||
<string name="android_auto_volume_unit_us_gallon" translatable="false">gal</string>
|
||||
<string name="android_auto_volume_unit_imperial_gallon" translatable="false">imp. gal</string>
|
||||
<!--Android Auto - Toll Card Strings -->
|
||||
<string name="android_auto_toll_card_title" translatable="false">Toll Card</string>
|
||||
<string name="android_auto_toll_card_state_base" translatable="false">The current state of the TollCard is %s</string>
|
||||
<string name="android_auto_toll_card_state_unknown" translatable="false">UNKNOWN</string>
|
||||
<string name="android_auto_toll_card_state_valid" translatable="false">VALID</string>
|
||||
<string name="android_auto_toll_card_state_invalid" translatable="false">INVALID</string>
|
||||
<string name="android_auto_toll_card_state_not_inserted" translatable="false">NOT_INSERTED</string>
|
||||
<!-- Android Auto - EnergyLevel -->
|
||||
<string name="android_auto_energy_level_title" translatable="false">Energy</string>
|
||||
<string name="android_auto_energy_level_battery_percentage_title" translatable="false">Battery \%</string>
|
||||
<string name="android_auto_energy_level_fuel_percentage_title" translatable="false">Fuel \%</string>
|
||||
<string name="android_auto_energy_level_range_remaining_title" translatable="false">Range Remaining</string>
|
||||
<string name="android_auto_energy_level_low_energy_title" translatable="false">Is low Energy?</string>
|
||||
<string name="android_auto_energy_level_battery_percentage_base" translatable="false">The battery is currently at %.2f\%</string>
|
||||
<string name="android_auto_energy_level_fuel_percentage_base" translatable="false">The current fuel level is at %.2f\%</string>
|
||||
<string name="android_auto_energy_level_low_energy_true" translatable="false">The car is currently in energy warning more</string>
|
||||
<string name="android_auto_energy_level_low_energy_false" translatable="false">The care operates normal and energy is fine</string>
|
||||
<string name="android_auto_energy_level_range_remaining_base" translatable="false">Range remaining: %.2f %s</string>
|
||||
<!-- Android Auto - EV-Status -->
|
||||
<string name="android_auto_ev_status_charge_port_connected_title" translatable="false">ChargePort Connection</string>
|
||||
<string name="android_auto_ev_status_charge_port_connected_true" translatable="false">Charge Port is currently connected</string>
|
||||
<string name="android_auto_ev_status_charge_port_connected_false" translatable="false">Charge Port is currently disconnected</string>
|
||||
<string name="android_auto_ev_status_charge_port_open_title" translatable="false">Charge Port Open</string>
|
||||
<string name="android_auto_ev_status_charge_port_open_true" translatable="false">Charge Port is currently open</string>
|
||||
<string name="android_auto_ev_status_charge_port_open_false" translatable="false">Charge Port is currently closed</string>
|
||||
<!-- Android Auto - Mileage -->
|
||||
<string name="android_auto_mileage_title" translatable="false">Odometer</string>
|
||||
<string name="android_auto_ev_mileage_odometer_base" translatable="false">Current Odometer Value is %.2f %s</string>
|
||||
<!-- Android Auto - Model -->
|
||||
<string name="android_auto_model_manufacturer_title" translatable="false">Manufacturer</string>
|
||||
<string name="android_auto_model_manufacturer_base" translatable="false">The Car-Manufacturer is %s</string>
|
||||
<string name="android_auto_model_name_title" translatable="false">Model Name</string>
|
||||
<string name="android_auto_model_name_base" translatable="false">The Car-Name is %s</string>
|
||||
<string name="android_auto_model_year_title" translatable="false">Model Year</string>
|
||||
<string name="android_auto_model_year_base" translatable="false">The Car was built in %d</string>
|
||||
<!-- Android Auto - Energy Profile -->
|
||||
<string name="android_auto_energy_profile_fuel_type_title" translatable="false">Fuel Type</string>
|
||||
<string name="android_auto_energy_profile_fuel_type_base" translatable="false">Supported Fuel Types: %s</string>
|
||||
<string name="android_auto_energy_profile_connector_type_title" translatable="false">EV-Connectors</string>
|
||||
<string name="android_auto_energy_profile_connector_type_base" translatable="false">Supported Connector Types: %s</string>
|
||||
<!-- Android Auto - FuelType -->
|
||||
<string name="android_auto_fuel_type_unknown" translatable="false">Unknown</string>
|
||||
<string name="android_auto_fuel_type_unleaded" translatable="false">Unleaded Gasoline</string>
|
||||
<string name="android_auto_fuel_type_leaded" translatable="false">Leaded Gasoline</string>
|
||||
<string name="android_auto_fuel_type_diesel_1" translatable="false">#1 Grade Diesel</string>
|
||||
<string name="android_auto_fuel_type_diesel_2" translatable="false">#2 Grade Diesel</string>
|
||||
<string name="android_auto_fuel_type_biodiesel" translatable="false">Biodiesel</string>
|
||||
<string name="android_auto_fuel_type_e85" translatable="false">85% ethanol/gasoline blend</string>
|
||||
<string name="android_auto_fuel_type_lpg" translatable="false">Liquified Petroleum Gas</string>
|
||||
<string name="android_auto_fuel_type_cng" translatable="false">Compressed Natural Gas</string>
|
||||
<string name="android_auto_fuel_type_lng" translatable="false">Liquified Natural Gas</string>
|
||||
<string name="android_auto_fuel_type_electric" translatable="false">Electric</string>
|
||||
<string name="android_auto_fuel_type_hydrogen" translatable="false">Hydrogen Fuel Cell</string>
|
||||
<string name="android_auto_fuel_type_other" translatable="false">Other</string>
|
||||
<!-- Android Auto - EV-ConnectorType -->
|
||||
<string name="android_auto_ev_connector_unknown" translatable="false">Unknown</string>
|
||||
<string name="android_auto_ev_connector_j1772" translatable="false">SAE J1772</string>
|
||||
<string name="android_auto_ev_connector_mennekes" translatable="false">IEC 62196 Type 2</string>
|
||||
<string name="android_auto_ev_connector_chademo" translatable="false">CHAdeMo Fast Charger</string>
|
||||
<string name="android_auto_ev_connector_combo_1" translatable="false">Combined Charging System Combo 1</string>
|
||||
<string name="android_auto_ev_connector_combo_2" translatable="false">Combined Charging System Combo 2</string>
|
||||
<string name="android_auto_ev_connector_tesla_roadster" translatable="false">Tesla Roadster</string>
|
||||
<string name="android_auto_ev_connector_tesla_hpwc" translatable="false">Tesla High Power Wall Charger</string>
|
||||
<string name="android_auto_ev_connector_tesla_supercharger" translatable="false">Tesla Supercharger</string>
|
||||
<string name="android_auto_ev_connector_gbt" translatable="false">GBT_AC Fast Charging Standard</string>
|
||||
<string name="android_auto_ev_connector_gbt_dc" translatable="false">GBT_DC Fast Charging Standard</string>
|
||||
<string name="android_auto_ev_connector_scame" translatable="false">IEC_TYPE_3_AC connector</string>
|
||||
<string name="android_auto_ev_connector_other" translatable="false">Other</string>
|
||||
|
||||
|
||||
</resources>
|
||||
Reference in New Issue
Block a user