1 /* 2 * Copyright (C) 2009 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 package com.android.providers.contacts; 17 18 import android.content.ContentValues; 19 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 20 import android.text.TextUtils; 21 22 import java.util.Locale; 23 24 /** 25 * Split and join {@link StructuredPostal} fields. 26 */ 27 public class PostalSplitter { 28 private static final String JAPANESE_LANGUAGE = Locale.JAPANESE.getLanguage().toLowerCase(); 29 30 private final Locale mLocale; 31 32 public static class Postal { 33 public String street; 34 public String pobox; 35 public String neighborhood; 36 public String city; 37 public String region; 38 public String postcode; 39 public String country; 40 41 public void fromValues(ContentValues values) { 42 street = values.getAsString(StructuredPostal.STREET); 43 pobox = values.getAsString(StructuredPostal.POBOX); 44 neighborhood = values.getAsString(StructuredPostal.NEIGHBORHOOD); 45 city = values.getAsString(StructuredPostal.CITY); 46 region = values.getAsString(StructuredPostal.REGION); 47 postcode = values.getAsString(StructuredPostal.POSTCODE); 48 country = values.getAsString(StructuredPostal.COUNTRY); 49 } 50 51 public void toValues(ContentValues values) { 52 values.put(StructuredPostal.STREET, street); 53 values.put(StructuredPostal.POBOX, pobox); 54 values.put(StructuredPostal.NEIGHBORHOOD, neighborhood); 55 values.put(StructuredPostal.CITY, city); 56 values.put(StructuredPostal.REGION, region); 57 values.put(StructuredPostal.POSTCODE, postcode); 58 values.put(StructuredPostal.COUNTRY, country); 59 } 60 } 61 62 public PostalSplitter(Locale locale) { 63 mLocale = locale; 64 } 65 66 /** 67 * Parses {@link StructuredPostal#FORMATTED_ADDRESS} and returns parsed 68 * components in the {@link Postal} object. 69 */ 70 public void split(Postal postal, String formattedAddress) { 71 if (!TextUtils.isEmpty(formattedAddress)) { 72 postal.street = formattedAddress; 73 } 74 } 75 76 private static final String NEWLINE = "\n"; 77 private static final String COMMA = ","; 78 private static final String SPACE = " "; 79 80 /** 81 * Flattens the given {@link Postal} into a single field, usually for 82 * storage in {@link StructuredPostal#FORMATTED_ADDRESS}. 83 */ 84 public String join(Postal postal) { 85 final String[] values = new String[] { 86 postal.street, postal.pobox, postal.neighborhood, postal.city, 87 postal.region, postal.postcode, postal.country 88 }; 89 // TODO: split off to handle various locales 90 if (mLocale != null && 91 JAPANESE_LANGUAGE.equals(mLocale.getLanguage()) && 92 !arePrintableAsciiOnly(values)) { 93 return joinJaJp(postal); 94 } else { 95 return joinEnUs(postal); 96 } 97 } 98 99 private String joinJaJp(final Postal postal) { 100 final boolean hasStreet = !TextUtils.isEmpty(postal.street); 101 final boolean hasPobox = !TextUtils.isEmpty(postal.pobox); 102 final boolean hasNeighborhood = !TextUtils.isEmpty(postal.neighborhood); 103 final boolean hasCity = !TextUtils.isEmpty(postal.city); 104 final boolean hasRegion = !TextUtils.isEmpty(postal.region); 105 final boolean hasPostcode = !TextUtils.isEmpty(postal.postcode); 106 final boolean hasCountry = !TextUtils.isEmpty(postal.country); 107 108 // First block: [country][ ][postcode] 109 // Second block: [region][ ][city][ ][neighborhood] 110 // Third block: [street][ ][pobox] 111 112 final StringBuilder builder = new StringBuilder(); 113 114 final boolean hasFirstBlock = hasCountry || hasPostcode; 115 final boolean hasSecondBlock = hasRegion || hasCity || hasNeighborhood; 116 final boolean hasThirdBlock = hasStreet || hasPobox; 117 118 if (hasFirstBlock) { 119 if (hasCountry) { 120 builder.append(postal.country); 121 } 122 if (hasPostcode) { 123 if (hasCountry) builder.append(SPACE); 124 builder.append(postal.postcode); 125 } 126 } 127 128 if (hasSecondBlock) { 129 if (hasFirstBlock) { 130 builder.append(NEWLINE); 131 } 132 if (hasRegion) { 133 builder.append(postal.region); 134 } 135 if (hasCity) { 136 if (hasRegion) builder.append(SPACE); 137 builder.append(postal.city); 138 } 139 if (hasNeighborhood) { 140 if (hasRegion || hasCity) builder.append(SPACE); 141 builder.append(postal.neighborhood); 142 } 143 } 144 145 if (hasThirdBlock) { 146 if (hasFirstBlock || hasSecondBlock) { 147 builder.append(NEWLINE); 148 } 149 if (hasStreet) { 150 builder.append(postal.street); 151 } 152 if (hasPobox) { 153 if (hasStreet) builder.append(SPACE); 154 builder.append(postal.pobox); 155 } 156 } 157 158 if (builder.length() > 0) { 159 return builder.toString(); 160 } else { 161 return null; 162 } 163 } 164 165 private String joinEnUs(final Postal postal) { 166 final boolean hasStreet = !TextUtils.isEmpty(postal.street); 167 final boolean hasPobox = !TextUtils.isEmpty(postal.pobox); 168 final boolean hasNeighborhood = !TextUtils.isEmpty(postal.neighborhood); 169 final boolean hasCity = !TextUtils.isEmpty(postal.city); 170 final boolean hasRegion = !TextUtils.isEmpty(postal.region); 171 final boolean hasPostcode = !TextUtils.isEmpty(postal.postcode); 172 final boolean hasCountry = !TextUtils.isEmpty(postal.country); 173 174 // First block: [street][\n][pobox][\n][neighborhood] 175 // Second block: [city][, ][region][ ][postcode] 176 // Third block: [country] 177 178 final StringBuilder builder = new StringBuilder(); 179 180 final boolean hasFirstBlock = hasStreet || hasPobox || hasNeighborhood; 181 final boolean hasSecondBlock = hasCity || hasRegion || hasPostcode; 182 final boolean hasThirdBlock = hasCountry; 183 184 if (hasFirstBlock) { 185 if (hasStreet) { 186 builder.append(postal.street); 187 } 188 if (hasPobox) { 189 if (hasStreet) builder.append(NEWLINE); 190 builder.append(postal.pobox); 191 } 192 if (hasNeighborhood) { 193 if (hasStreet || hasPobox) builder.append(NEWLINE); 194 builder.append(postal.neighborhood); 195 } 196 } 197 198 if (hasSecondBlock) { 199 if (hasFirstBlock) { 200 builder.append(NEWLINE); 201 } 202 if (hasCity) { 203 builder.append(postal.city); 204 } 205 if (hasRegion) { 206 if (hasCity) builder.append(COMMA + SPACE); 207 builder.append(postal.region); 208 } 209 if (hasPostcode) { 210 if (hasCity || hasRegion) builder.append(SPACE); 211 builder.append(postal.postcode); 212 } 213 } 214 215 if (hasThirdBlock) { 216 if (hasFirstBlock || hasSecondBlock) { 217 builder.append(NEWLINE); 218 } 219 if (hasCountry) { 220 builder.append(postal.country); 221 } 222 } 223 224 if (builder.length() > 0) { 225 return builder.toString(); 226 } else { 227 return null; 228 } 229 } 230 231 private static boolean arePrintableAsciiOnly(final String[] values) { 232 if (values == null) { 233 return true; 234 } 235 for (final String value : values) { 236 if (TextUtils.isEmpty(value)) { 237 continue; 238 } 239 if (!TextUtils.isPrintableAsciiOnly(value)) { 240 return false; 241 } 242 } 243 return true; 244 } 245 } 246