ContactLookupKey.java revision 5870f2dcc2ac7715b2c078a886ee346622e7887e
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 17package com.android.providers.contacts; 18 19import android.net.Uri; 20 21import java.util.ArrayList; 22 23/** 24 * Contacts lookup key. Used for generation and parsing of contact lookup keys as well 25 * as doing the actual lookup. 26 */ 27public class ContactLookupKey { 28 29 public static class LookupKeySegment implements Comparable<LookupKeySegment> { 30 public int accountHashCode; 31 public boolean sourceIdLookup; 32 public String key; 33 public long contactId; 34 35 public int compareTo(LookupKeySegment another) { 36 if (contactId > another.contactId) { 37 return -1; 38 } 39 if (contactId < another.contactId) { 40 return 1; 41 } 42 return 0; 43 } 44 } 45 46 /** 47 * Returns a short hash code that functions as an additional precaution against the exceedingly 48 * improbable collision between sync IDs in different accounts. 49 */ 50 public static int getAccountHashCode(String accountType, String accountName) { 51 if (accountType == null || accountName == null) { 52 return 0; 53 } 54 55 return (accountType.hashCode() ^ accountName.hashCode()) & 0xFFF; 56 } 57 58 public static void appendToLookupKey(StringBuffer lookupKey, String accountType, 59 String accountName, String sourceId, String displayName) { 60 if (lookupKey.length() != 0) { 61 lookupKey.append("."); 62 } 63 64 lookupKey.append(getAccountHashCode(accountType, accountName)); 65 if (sourceId == null) { 66 lookupKey.append('n').append(NameNormalizer.normalize(displayName)); 67 } else { 68 int pos = lookupKey.length(); 69 lookupKey.append('i'); 70 if (appendEscapedSourceId(lookupKey, sourceId)) { 71 lookupKey.setCharAt(pos, 'e'); 72 } 73 } 74 } 75 76 private static boolean appendEscapedSourceId(StringBuffer sb, String sourceId) { 77 boolean escaped = false; 78 int start = 0; 79 while (true) { 80 int index = sourceId.indexOf('.', start); 81 if (index == -1) { 82 sb.append(sourceId, start, sourceId.length()); 83 break; 84 } 85 86 escaped = true; 87 sb.append(sourceId, start, index); 88 sb.append(".."); 89 start = index + 1; 90 } 91 return escaped; 92 } 93 94 public ArrayList<LookupKeySegment> parse(String lookupKey) { 95 ArrayList<LookupKeySegment> list = new ArrayList<LookupKeySegment>(); 96 97 String string = Uri.decode(lookupKey); 98 int offset = 0; 99 int length = string.length(); 100 int hashCode = 0; 101 boolean sourceIdLookup = false; 102 boolean escaped; 103 String key; 104 105 while (offset < length) { 106 char c = 0; 107 108 // Parse account hash code 109 hashCode = 0; 110 while (offset < length) { 111 c = string.charAt(offset++); 112 if (c < '0' || c > '9') { 113 break; 114 } 115 hashCode = hashCode * 10 + (c - '0'); 116 } 117 118 // Parse segment type 119 if (c == 'n') { 120 sourceIdLookup = false; 121 escaped = false; 122 } else if (c == 'i') { 123 sourceIdLookup = true; 124 escaped = false; 125 } else if (c == 'e') { 126 sourceIdLookup = true; 127 escaped = true; 128 } else { 129 throw new IllegalArgumentException("Invalid lookup id: " + lookupKey); 130 } 131 132 // Parse the source ID or normalized display name 133 if (escaped) { 134 StringBuffer sb = new StringBuffer(); 135 while (offset < length) { 136 c = string.charAt(offset++); 137 138 if (c == '.') { 139 if (offset == length) { 140 throw new IllegalArgumentException("Invalid lookup id: " + lookupKey); 141 } 142 c = string.charAt(offset); 143 144 if (c == '.') { 145 sb.append('.'); 146 offset++; 147 } else { 148 break; 149 } 150 } else { 151 sb.append(c); 152 } 153 } 154 key = sb.toString(); 155 } else { 156 int start = offset; 157 while (offset < length) { 158 c = string.charAt(offset++); 159 160 if (c == '.') { 161 break; 162 } 163 } 164 if (offset == length) { 165 key = string.substring(start); 166 } else { 167 key = string.substring(start, offset - 1); 168 } 169 } 170 171 LookupKeySegment segment = new LookupKeySegment(); 172 segment.accountHashCode = hashCode; 173 segment.key = key; 174 segment.sourceIdLookup = sourceIdLookup; 175 segment.contactId = -1; 176 list.add(segment); 177 } 178 179 return list; 180 } 181} 182