Home | History | Annotate | Download | only in contacts
      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