1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.carlauncher.calmmode; 18 19 import android.car.cluster.navigation.NavigationState; 20 import android.icu.number.Notation; 21 import android.icu.number.NumberFormatter; 22 import android.icu.number.Precision; 23 import android.icu.util.MeasureUnit; 24 import android.os.Build; 25 import android.util.Log; 26 27 import androidx.annotation.NonNull; 28 import androidx.annotation.Nullable; 29 30 import java.util.Locale; 31 32 public class NavigationStateData { 33 private static final boolean DEBUG = Build.isDebuggable(); 34 private static final String TAG = NavigationStateData.class.getSimpleName(); 35 @NonNull 36 private final String mTimeToDestination; 37 38 private double mDistanceToDestination; 39 @NonNull 40 private MeasureUnit mDistanceUnit; NavigationStateData( @onNull String timeToDestination, double distanceToDestination, @NonNull MeasureUnit distanceUnit)41 private NavigationStateData( 42 @NonNull String timeToDestination, 43 double distanceToDestination, 44 @NonNull MeasureUnit distanceUnit) { 45 this.mTimeToDestination = timeToDestination; 46 this.mDistanceToDestination = distanceToDestination; 47 this.mDistanceUnit = distanceUnit; 48 } 49 50 /** 51 * @return new {@link Builder} instance for creating {@link NavigationStateData} 52 */ 53 @NonNull newBuilder()54 public static Builder newBuilder() { 55 return new Builder(); 56 } 57 58 /** 59 * Trip Status is a string containing time and distance remaining to reach next destination 60 * Example: "1hr 52 min | 100mi" 61 * @param navigationState {@link NavigationStateData} to use for building Trip Status string 62 * @param locale {@link Locale} to build Trip Status string 63 * @param separator Separator used to separate time and distance 64 * @return String representing trip status with time and distance to next destination, returns 65 * null if arguments are invalid, uses {@link Locale#getDefault()} if {@code locale} is null 66 */ 67 @Nullable buildTripStatusString( @onNull NavigationStateData navigationState, @NonNull Locale locale, @NonNull String separator)68 public static String buildTripStatusString( 69 @NonNull NavigationStateData navigationState, @NonNull Locale locale, 70 @NonNull String separator) { 71 72 if (navigationState == null 73 || navigationState.getTimeToDestination() == null 74 || navigationState.getDistanceUnit() == null) { 75 if (DEBUG) { 76 Log.w( 77 TAG, 78 "buildTripStatusString: invalid argument navigationState= " 79 + navigationState 80 + ", returning null"); 81 } 82 return null; 83 } 84 if (locale == null) { 85 if (DEBUG) { 86 Log.w(TAG, "buildTripStatusString: locale is null, returning null"); 87 } 88 locale = Locale.getDefault(); 89 } 90 StringBuilder navStateTextBuilder = new StringBuilder(); 91 navStateTextBuilder.append(navigationState.getTimeToDestination()); 92 navStateTextBuilder.append(separator); 93 navStateTextBuilder.append(NumberFormatter.withLocale(locale) 94 .notation(Notation.compactShort()) 95 .precision(Precision.integer()) 96 .unit(navigationState.getDistanceUnit()) 97 .format(navigationState.getDistanceToDestination()) 98 .toString()); 99 return navStateTextBuilder.toString(); 100 } 101 102 @NonNull getTimeToDestination()103 public String getTimeToDestination() { 104 return mTimeToDestination; 105 } 106 getDistanceToDestination()107 public double getDistanceToDestination() { 108 return mDistanceToDestination; 109 } 110 @NonNull getDistanceUnit()111 public MeasureUnit getDistanceUnit() { 112 return mDistanceUnit; 113 } 114 115 @Override toString()116 public String toString() { 117 return "NavigationStateData{" 118 + " timeToDestination='" + mTimeToDestination + '\'' 119 + ", distanceToDestination=" + mDistanceToDestination 120 + ", distanceUnit=" + mDistanceUnit 121 + '}'; 122 } 123 124 public static class Builder { 125 private String mTimeToDestination; 126 private double mDistanceToDestination; 127 private MeasureUnit mDistanceUnit; 128 129 /** 130 * @param timeToDestination String representation of time remaining to next destination 131 * Example: 1hr 52min 132 * @return {@link Builder} object 133 */ setTimeToDestination(@onNull String timeToDestination)134 public Builder setTimeToDestination(@NonNull String timeToDestination) { 135 this.mTimeToDestination = timeToDestination; 136 return this; 137 } 138 139 /** 140 * @param distanceToDestination String representation of distance remaining to next 141 * destination. Example: "20" This is designed to be compatible with {@link 142 * android.car.cluster.navigation.NavigationState.Distance} 143 * @return {@link Builder} object 144 * @throws NumberFormatException if the {@code distanceToDestination} is not a 145 * number 146 */ setDistanceToDestination(@onNull String distanceToDestination)147 public Builder setDistanceToDestination(@NonNull String distanceToDestination) 148 throws NumberFormatException { 149 this.mDistanceToDestination = Double.parseDouble(distanceToDestination); 150 return this; 151 } 152 153 /** 154 * @param distanceUnit {@link NavigationState.Distance.Unit} Unit for distance 155 * @return {@link Builder} object 156 * @throws IllegalArgumentException if the {@code distanceUnit} is not a recognized 157 * {@link NavigationState.Distance.Unit} 158 */ setDistanceUnit(@onNull NavigationState.Distance.Unit distanceUnit)159 public Builder setDistanceUnit(@NonNull NavigationState.Distance.Unit distanceUnit) 160 throws IllegalArgumentException { 161 MeasureUnit unit = null; 162 switch (distanceUnit) { 163 case FEET: unit = MeasureUnit.FOOT; break; 164 case YARDS: unit = MeasureUnit.YARD; break; 165 case KILOMETERS: unit = MeasureUnit.KILOMETER; break; 166 case METERS: unit = MeasureUnit.METER; break; 167 case MILES: unit = MeasureUnit.MILE; break; 168 default: break; 169 } 170 if (unit == null) { 171 throw new IllegalArgumentException("Unrecognized NavigationState.Distance.Unit, " 172 + "unable to create NavigationStateData.Builder"); 173 } 174 this.mDistanceUnit = unit; 175 return this; 176 } 177 178 /** Builds a {@link NavigationStateData} 179 * @return {@link NavigationStateData} object 180 */ 181 @NonNull build()182 public NavigationStateData build() { 183 return new NavigationStateData( 184 mTimeToDestination, mDistanceToDestination, mDistanceUnit); 185 } 186 187 } 188 189 } 190