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