Messaging: Vendor chips, colorpicker, photoviewer, and vcard in-tree
Clone no longer depends on LineageOS gitlinks; the libraries used by the app live in this repo. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Submodule modules/vcard deleted from f049d8cd3a
@@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2010 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "com.android.vcard",
|
||||
|
||||
// 2.3
|
||||
sdk_version: "9",
|
||||
|
||||
srcs: ["java/**/*.java"],
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"com.android.bt",
|
||||
],
|
||||
|
||||
libs: [
|
||||
"framework-annotations-lib",
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
||||
@@ -0,0 +1,3 @@
|
||||
# Default code reviewers picked from top 3 or more developers.
|
||||
# Please update this list if you find better candidates.
|
||||
johnshao@google.com
|
||||
@@ -0,0 +1,29 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.android.vcard'
|
||||
compileSdk 35
|
||||
|
||||
defaultConfig {
|
||||
minSdk 33
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = ['java']
|
||||
res.srcDirs = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.annotation:annotation:1.8.2'
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TextUtils especially for Japanese.
|
||||
*/
|
||||
/* package */ class JapaneseUtils {
|
||||
@VisibleForTesting
|
||||
static final Map<Character, String> sHalfWidthMap =
|
||||
new HashMap<Character, String>();
|
||||
|
||||
static {
|
||||
sHalfWidthMap.put('\u3001', "\uFF64");
|
||||
sHalfWidthMap.put('\u3002', "\uFF61");
|
||||
sHalfWidthMap.put('\u300C', "\uFF62");
|
||||
sHalfWidthMap.put('\u300D', "\uFF63");
|
||||
sHalfWidthMap.put('\u301C', "~");
|
||||
sHalfWidthMap.put('\u3041', "\uFF67");
|
||||
sHalfWidthMap.put('\u3042', "\uFF71");
|
||||
sHalfWidthMap.put('\u3043', "\uFF68");
|
||||
sHalfWidthMap.put('\u3044', "\uFF72");
|
||||
sHalfWidthMap.put('\u3045', "\uFF69");
|
||||
sHalfWidthMap.put('\u3046', "\uFF73");
|
||||
sHalfWidthMap.put('\u3047', "\uFF6A");
|
||||
sHalfWidthMap.put('\u3048', "\uFF74");
|
||||
sHalfWidthMap.put('\u3049', "\uFF6B");
|
||||
sHalfWidthMap.put('\u304A', "\uFF75");
|
||||
sHalfWidthMap.put('\u304B', "\uFF76");
|
||||
sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
|
||||
sHalfWidthMap.put('\u304D', "\uFF77");
|
||||
sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
|
||||
sHalfWidthMap.put('\u304F', "\uFF78");
|
||||
sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
|
||||
sHalfWidthMap.put('\u3051', "\uFF79");
|
||||
sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
|
||||
sHalfWidthMap.put('\u3053', "\uFF7A");
|
||||
sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
|
||||
sHalfWidthMap.put('\u3055', "\uFF7B");
|
||||
sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
|
||||
sHalfWidthMap.put('\u3057', "\uFF7C");
|
||||
sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
|
||||
sHalfWidthMap.put('\u3059', "\uFF7D");
|
||||
sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
|
||||
sHalfWidthMap.put('\u305B', "\uFF7E");
|
||||
sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
|
||||
sHalfWidthMap.put('\u305D', "\uFF7F");
|
||||
sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
|
||||
sHalfWidthMap.put('\u305F', "\uFF80");
|
||||
sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
|
||||
sHalfWidthMap.put('\u3061', "\uFF81");
|
||||
sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
|
||||
sHalfWidthMap.put('\u3063', "\uFF6F");
|
||||
sHalfWidthMap.put('\u3064', "\uFF82");
|
||||
sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
|
||||
sHalfWidthMap.put('\u3066', "\uFF83");
|
||||
sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
|
||||
sHalfWidthMap.put('\u3068', "\uFF84");
|
||||
sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
|
||||
sHalfWidthMap.put('\u306A', "\uFF85");
|
||||
sHalfWidthMap.put('\u306B', "\uFF86");
|
||||
sHalfWidthMap.put('\u306C', "\uFF87");
|
||||
sHalfWidthMap.put('\u306D', "\uFF88");
|
||||
sHalfWidthMap.put('\u306E', "\uFF89");
|
||||
sHalfWidthMap.put('\u306F', "\uFF8A");
|
||||
sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
|
||||
sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
|
||||
sHalfWidthMap.put('\u3072', "\uFF8B");
|
||||
sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
|
||||
sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
|
||||
sHalfWidthMap.put('\u3075', "\uFF8C");
|
||||
sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
|
||||
sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
|
||||
sHalfWidthMap.put('\u3078', "\uFF8D");
|
||||
sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
|
||||
sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
|
||||
sHalfWidthMap.put('\u307B', "\uFF8E");
|
||||
sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
|
||||
sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
|
||||
sHalfWidthMap.put('\u307E', "\uFF8F");
|
||||
sHalfWidthMap.put('\u307F', "\uFF90");
|
||||
sHalfWidthMap.put('\u3080', "\uFF91");
|
||||
sHalfWidthMap.put('\u3081', "\uFF92");
|
||||
sHalfWidthMap.put('\u3082', "\uFF93");
|
||||
sHalfWidthMap.put('\u3083', "\uFF6C");
|
||||
sHalfWidthMap.put('\u3084', "\uFF94");
|
||||
sHalfWidthMap.put('\u3085', "\uFF6D");
|
||||
sHalfWidthMap.put('\u3086', "\uFF95");
|
||||
sHalfWidthMap.put('\u3087', "\uFF6E");
|
||||
sHalfWidthMap.put('\u3088', "\uFF96");
|
||||
sHalfWidthMap.put('\u3089', "\uFF97");
|
||||
sHalfWidthMap.put('\u308A', "\uFF98");
|
||||
sHalfWidthMap.put('\u308B', "\uFF99");
|
||||
sHalfWidthMap.put('\u308C', "\uFF9A");
|
||||
sHalfWidthMap.put('\u308D', "\uFF9B");
|
||||
sHalfWidthMap.put('\u308E', "\uFF9C");
|
||||
sHalfWidthMap.put('\u308F', "\uFF9C");
|
||||
sHalfWidthMap.put('\u3090', "\uFF72");
|
||||
sHalfWidthMap.put('\u3091', "\uFF74");
|
||||
sHalfWidthMap.put('\u3092', "\uFF66");
|
||||
sHalfWidthMap.put('\u3093', "\uFF9D");
|
||||
sHalfWidthMap.put('\u309B', "\uFF9E");
|
||||
sHalfWidthMap.put('\u309C', "\uFF9F");
|
||||
sHalfWidthMap.put('\u30A1', "\uFF67");
|
||||
sHalfWidthMap.put('\u30A2', "\uFF71");
|
||||
sHalfWidthMap.put('\u30A3', "\uFF68");
|
||||
sHalfWidthMap.put('\u30A4', "\uFF72");
|
||||
sHalfWidthMap.put('\u30A5', "\uFF69");
|
||||
sHalfWidthMap.put('\u30A6', "\uFF73");
|
||||
sHalfWidthMap.put('\u30A7', "\uFF6A");
|
||||
sHalfWidthMap.put('\u30A8', "\uFF74");
|
||||
sHalfWidthMap.put('\u30A9', "\uFF6B");
|
||||
sHalfWidthMap.put('\u30AA', "\uFF75");
|
||||
sHalfWidthMap.put('\u30AB', "\uFF76");
|
||||
sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
|
||||
sHalfWidthMap.put('\u30AD', "\uFF77");
|
||||
sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
|
||||
sHalfWidthMap.put('\u30AF', "\uFF78");
|
||||
sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
|
||||
sHalfWidthMap.put('\u30B1', "\uFF79");
|
||||
sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
|
||||
sHalfWidthMap.put('\u30B3', "\uFF7A");
|
||||
sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
|
||||
sHalfWidthMap.put('\u30B5', "\uFF7B");
|
||||
sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
|
||||
sHalfWidthMap.put('\u30B7', "\uFF7C");
|
||||
sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
|
||||
sHalfWidthMap.put('\u30B9', "\uFF7D");
|
||||
sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
|
||||
sHalfWidthMap.put('\u30BB', "\uFF7E");
|
||||
sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
|
||||
sHalfWidthMap.put('\u30BD', "\uFF7F");
|
||||
sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
|
||||
sHalfWidthMap.put('\u30BF', "\uFF80");
|
||||
sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
|
||||
sHalfWidthMap.put('\u30C1', "\uFF81");
|
||||
sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
|
||||
sHalfWidthMap.put('\u30C3', "\uFF6F");
|
||||
sHalfWidthMap.put('\u30C4', "\uFF82");
|
||||
sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
|
||||
sHalfWidthMap.put('\u30C6', "\uFF83");
|
||||
sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
|
||||
sHalfWidthMap.put('\u30C8', "\uFF84");
|
||||
sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
|
||||
sHalfWidthMap.put('\u30CA', "\uFF85");
|
||||
sHalfWidthMap.put('\u30CB', "\uFF86");
|
||||
sHalfWidthMap.put('\u30CC', "\uFF87");
|
||||
sHalfWidthMap.put('\u30CD', "\uFF88");
|
||||
sHalfWidthMap.put('\u30CE', "\uFF89");
|
||||
sHalfWidthMap.put('\u30CF', "\uFF8A");
|
||||
sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
|
||||
sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
|
||||
sHalfWidthMap.put('\u30D2', "\uFF8B");
|
||||
sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
|
||||
sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
|
||||
sHalfWidthMap.put('\u30D5', "\uFF8C");
|
||||
sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
|
||||
sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
|
||||
sHalfWidthMap.put('\u30D8', "\uFF8D");
|
||||
sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
|
||||
sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
|
||||
sHalfWidthMap.put('\u30DB', "\uFF8E");
|
||||
sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
|
||||
sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
|
||||
sHalfWidthMap.put('\u30DE', "\uFF8F");
|
||||
sHalfWidthMap.put('\u30DF', "\uFF90");
|
||||
sHalfWidthMap.put('\u30E0', "\uFF91");
|
||||
sHalfWidthMap.put('\u30E1', "\uFF92");
|
||||
sHalfWidthMap.put('\u30E2', "\uFF93");
|
||||
sHalfWidthMap.put('\u30E3', "\uFF6C");
|
||||
sHalfWidthMap.put('\u30E4', "\uFF94");
|
||||
sHalfWidthMap.put('\u30E5', "\uFF6D");
|
||||
sHalfWidthMap.put('\u30E6', "\uFF95");
|
||||
sHalfWidthMap.put('\u30E7', "\uFF6E");
|
||||
sHalfWidthMap.put('\u30E8', "\uFF96");
|
||||
sHalfWidthMap.put('\u30E9', "\uFF97");
|
||||
sHalfWidthMap.put('\u30EA', "\uFF98");
|
||||
sHalfWidthMap.put('\u30EB', "\uFF99");
|
||||
sHalfWidthMap.put('\u30EC', "\uFF9A");
|
||||
sHalfWidthMap.put('\u30ED', "\uFF9B");
|
||||
sHalfWidthMap.put('\u30EE', "\uFF9C");
|
||||
sHalfWidthMap.put('\u30EF', "\uFF9C");
|
||||
sHalfWidthMap.put('\u30F0', "\uFF72");
|
||||
sHalfWidthMap.put('\u30F1', "\uFF74");
|
||||
sHalfWidthMap.put('\u30F2', "\uFF66");
|
||||
sHalfWidthMap.put('\u30F3', "\uFF9D");
|
||||
sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
|
||||
sHalfWidthMap.put('\u30F5', "\uFF76");
|
||||
sHalfWidthMap.put('\u30F6', "\uFF79");
|
||||
sHalfWidthMap.put('\u30FB', "\uFF65");
|
||||
sHalfWidthMap.put('\u30FC', "\uFF70");
|
||||
sHalfWidthMap.put('\uFF01', "!");
|
||||
sHalfWidthMap.put('\uFF02', "\"");
|
||||
sHalfWidthMap.put('\uFF03', "#");
|
||||
sHalfWidthMap.put('\uFF04', "$");
|
||||
sHalfWidthMap.put('\uFF05', "%");
|
||||
sHalfWidthMap.put('\uFF06', "&");
|
||||
sHalfWidthMap.put('\uFF07', "'");
|
||||
sHalfWidthMap.put('\uFF08', "(");
|
||||
sHalfWidthMap.put('\uFF09', ")");
|
||||
sHalfWidthMap.put('\uFF0A', "*");
|
||||
sHalfWidthMap.put('\uFF0B', "+");
|
||||
sHalfWidthMap.put('\uFF0C', ",");
|
||||
sHalfWidthMap.put('\uFF0D', "-");
|
||||
sHalfWidthMap.put('\uFF0E', ".");
|
||||
sHalfWidthMap.put('\uFF0F', "/");
|
||||
sHalfWidthMap.put('\uFF10', "0");
|
||||
sHalfWidthMap.put('\uFF11', "1");
|
||||
sHalfWidthMap.put('\uFF12', "2");
|
||||
sHalfWidthMap.put('\uFF13', "3");
|
||||
sHalfWidthMap.put('\uFF14', "4");
|
||||
sHalfWidthMap.put('\uFF15', "5");
|
||||
sHalfWidthMap.put('\uFF16', "6");
|
||||
sHalfWidthMap.put('\uFF17', "7");
|
||||
sHalfWidthMap.put('\uFF18', "8");
|
||||
sHalfWidthMap.put('\uFF19', "9");
|
||||
sHalfWidthMap.put('\uFF1A', ":");
|
||||
sHalfWidthMap.put('\uFF1B', ";");
|
||||
sHalfWidthMap.put('\uFF1C', "<");
|
||||
sHalfWidthMap.put('\uFF1D', "=");
|
||||
sHalfWidthMap.put('\uFF1E', ">");
|
||||
sHalfWidthMap.put('\uFF1F', "?");
|
||||
sHalfWidthMap.put('\uFF20', "@");
|
||||
sHalfWidthMap.put('\uFF21', "A");
|
||||
sHalfWidthMap.put('\uFF22', "B");
|
||||
sHalfWidthMap.put('\uFF23', "C");
|
||||
sHalfWidthMap.put('\uFF24', "D");
|
||||
sHalfWidthMap.put('\uFF25', "E");
|
||||
sHalfWidthMap.put('\uFF26', "F");
|
||||
sHalfWidthMap.put('\uFF27', "G");
|
||||
sHalfWidthMap.put('\uFF28', "H");
|
||||
sHalfWidthMap.put('\uFF29', "I");
|
||||
sHalfWidthMap.put('\uFF2A', "J");
|
||||
sHalfWidthMap.put('\uFF2B', "K");
|
||||
sHalfWidthMap.put('\uFF2C', "L");
|
||||
sHalfWidthMap.put('\uFF2D', "M");
|
||||
sHalfWidthMap.put('\uFF2E', "N");
|
||||
sHalfWidthMap.put('\uFF2F', "O");
|
||||
sHalfWidthMap.put('\uFF30', "P");
|
||||
sHalfWidthMap.put('\uFF31', "Q");
|
||||
sHalfWidthMap.put('\uFF32', "R");
|
||||
sHalfWidthMap.put('\uFF33', "S");
|
||||
sHalfWidthMap.put('\uFF34', "T");
|
||||
sHalfWidthMap.put('\uFF35', "U");
|
||||
sHalfWidthMap.put('\uFF36', "V");
|
||||
sHalfWidthMap.put('\uFF37', "W");
|
||||
sHalfWidthMap.put('\uFF38', "X");
|
||||
sHalfWidthMap.put('\uFF39', "Y");
|
||||
sHalfWidthMap.put('\uFF3A', "Z");
|
||||
sHalfWidthMap.put('\uFF3B', "[");
|
||||
sHalfWidthMap.put('\uFF3C', "\\");
|
||||
sHalfWidthMap.put('\uFF3D', "]");
|
||||
sHalfWidthMap.put('\uFF3E', "^");
|
||||
sHalfWidthMap.put('\uFF3F', "_");
|
||||
sHalfWidthMap.put('\uFF41', "a");
|
||||
sHalfWidthMap.put('\uFF42', "b");
|
||||
sHalfWidthMap.put('\uFF43', "c");
|
||||
sHalfWidthMap.put('\uFF44', "d");
|
||||
sHalfWidthMap.put('\uFF45', "e");
|
||||
sHalfWidthMap.put('\uFF46', "f");
|
||||
sHalfWidthMap.put('\uFF47', "g");
|
||||
sHalfWidthMap.put('\uFF48', "h");
|
||||
sHalfWidthMap.put('\uFF49', "i");
|
||||
sHalfWidthMap.put('\uFF4A', "j");
|
||||
sHalfWidthMap.put('\uFF4B', "k");
|
||||
sHalfWidthMap.put('\uFF4C', "l");
|
||||
sHalfWidthMap.put('\uFF4D', "m");
|
||||
sHalfWidthMap.put('\uFF4E', "n");
|
||||
sHalfWidthMap.put('\uFF4F', "o");
|
||||
sHalfWidthMap.put('\uFF50', "p");
|
||||
sHalfWidthMap.put('\uFF51', "q");
|
||||
sHalfWidthMap.put('\uFF52', "r");
|
||||
sHalfWidthMap.put('\uFF53', "s");
|
||||
sHalfWidthMap.put('\uFF54', "t");
|
||||
sHalfWidthMap.put('\uFF55', "u");
|
||||
sHalfWidthMap.put('\uFF56', "v");
|
||||
sHalfWidthMap.put('\uFF57', "w");
|
||||
sHalfWidthMap.put('\uFF58', "x");
|
||||
sHalfWidthMap.put('\uFF59', "y");
|
||||
sHalfWidthMap.put('\uFF5A', "z");
|
||||
sHalfWidthMap.put('\uFF5B', "{");
|
||||
sHalfWidthMap.put('\uFF5C', "|");
|
||||
sHalfWidthMap.put('\uFF5D', "}");
|
||||
sHalfWidthMap.put('\uFF5E', "~");
|
||||
sHalfWidthMap.put('\uFF61', "\uFF61");
|
||||
sHalfWidthMap.put('\uFF62', "\uFF62");
|
||||
sHalfWidthMap.put('\uFF63', "\uFF63");
|
||||
sHalfWidthMap.put('\uFF64', "\uFF64");
|
||||
sHalfWidthMap.put('\uFF65', "\uFF65");
|
||||
sHalfWidthMap.put('\uFF66', "\uFF66");
|
||||
sHalfWidthMap.put('\uFF67', "\uFF67");
|
||||
sHalfWidthMap.put('\uFF68', "\uFF68");
|
||||
sHalfWidthMap.put('\uFF69', "\uFF69");
|
||||
sHalfWidthMap.put('\uFF6A', "\uFF6A");
|
||||
sHalfWidthMap.put('\uFF6B', "\uFF6B");
|
||||
sHalfWidthMap.put('\uFF6C', "\uFF6C");
|
||||
sHalfWidthMap.put('\uFF6D', "\uFF6D");
|
||||
sHalfWidthMap.put('\uFF6E', "\uFF6E");
|
||||
sHalfWidthMap.put('\uFF6F', "\uFF6F");
|
||||
sHalfWidthMap.put('\uFF70', "\uFF70");
|
||||
sHalfWidthMap.put('\uFF71', "\uFF71");
|
||||
sHalfWidthMap.put('\uFF72', "\uFF72");
|
||||
sHalfWidthMap.put('\uFF73', "\uFF73");
|
||||
sHalfWidthMap.put('\uFF74', "\uFF74");
|
||||
sHalfWidthMap.put('\uFF75', "\uFF75");
|
||||
sHalfWidthMap.put('\uFF76', "\uFF76");
|
||||
sHalfWidthMap.put('\uFF77', "\uFF77");
|
||||
sHalfWidthMap.put('\uFF78', "\uFF78");
|
||||
sHalfWidthMap.put('\uFF79', "\uFF79");
|
||||
sHalfWidthMap.put('\uFF7A', "\uFF7A");
|
||||
sHalfWidthMap.put('\uFF7B', "\uFF7B");
|
||||
sHalfWidthMap.put('\uFF7C', "\uFF7C");
|
||||
sHalfWidthMap.put('\uFF7D', "\uFF7D");
|
||||
sHalfWidthMap.put('\uFF7E', "\uFF7E");
|
||||
sHalfWidthMap.put('\uFF7F', "\uFF7F");
|
||||
sHalfWidthMap.put('\uFF80', "\uFF80");
|
||||
sHalfWidthMap.put('\uFF81', "\uFF81");
|
||||
sHalfWidthMap.put('\uFF82', "\uFF82");
|
||||
sHalfWidthMap.put('\uFF83', "\uFF83");
|
||||
sHalfWidthMap.put('\uFF84', "\uFF84");
|
||||
sHalfWidthMap.put('\uFF85', "\uFF85");
|
||||
sHalfWidthMap.put('\uFF86', "\uFF86");
|
||||
sHalfWidthMap.put('\uFF87', "\uFF87");
|
||||
sHalfWidthMap.put('\uFF88', "\uFF88");
|
||||
sHalfWidthMap.put('\uFF89', "\uFF89");
|
||||
sHalfWidthMap.put('\uFF8A', "\uFF8A");
|
||||
sHalfWidthMap.put('\uFF8B', "\uFF8B");
|
||||
sHalfWidthMap.put('\uFF8C', "\uFF8C");
|
||||
sHalfWidthMap.put('\uFF8D', "\uFF8D");
|
||||
sHalfWidthMap.put('\uFF8E', "\uFF8E");
|
||||
sHalfWidthMap.put('\uFF8F', "\uFF8F");
|
||||
sHalfWidthMap.put('\uFF90', "\uFF90");
|
||||
sHalfWidthMap.put('\uFF91', "\uFF91");
|
||||
sHalfWidthMap.put('\uFF92', "\uFF92");
|
||||
sHalfWidthMap.put('\uFF93', "\uFF93");
|
||||
sHalfWidthMap.put('\uFF94', "\uFF94");
|
||||
sHalfWidthMap.put('\uFF95', "\uFF95");
|
||||
sHalfWidthMap.put('\uFF96', "\uFF96");
|
||||
sHalfWidthMap.put('\uFF97', "\uFF97");
|
||||
sHalfWidthMap.put('\uFF98', "\uFF98");
|
||||
sHalfWidthMap.put('\uFF99', "\uFF99");
|
||||
sHalfWidthMap.put('\uFF9A', "\uFF9A");
|
||||
sHalfWidthMap.put('\uFF9B', "\uFF9B");
|
||||
sHalfWidthMap.put('\uFF9C', "\uFF9C");
|
||||
sHalfWidthMap.put('\uFF9D', "\uFF9D");
|
||||
sHalfWidthMap.put('\uFF9E', "\uFF9E");
|
||||
sHalfWidthMap.put('\uFF9F', "\uFF9F");
|
||||
sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns half-width version of that character if possible. Returns null if not possible
|
||||
* @param ch input character
|
||||
* @return CharSequence object if the mapping for ch exists. Return null otherwise.
|
||||
*/
|
||||
public static String tryGetHalfWidthText(final char ch) {
|
||||
if (sHalfWidthMap.containsKey(ch)) {
|
||||
return sHalfWidthMap.get(ch);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,721 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Entity;
|
||||
import android.content.Entity.NamedContentValues;
|
||||
import android.content.EntityIterator;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Event;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Im;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Nickname;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Note;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Organization;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Photo;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Relation;
|
||||
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Website;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.provider.ContactsContract.RawContactsEntity;
|
||||
import android.provider.ContactsContract;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The class for composing vCard from Contacts information.
|
||||
* </p>
|
||||
* <p>
|
||||
* Usually, this class should be used like this.
|
||||
* </p>
|
||||
* <pre class="prettyprint">VCardComposer composer = null;
|
||||
* try {
|
||||
* composer = new VCardComposer(context);
|
||||
* composer.addHandler(
|
||||
* composer.new HandlerForOutputStream(outputStream));
|
||||
* if (!composer.init()) {
|
||||
* // Do something handling the situation.
|
||||
* return;
|
||||
* }
|
||||
* while (!composer.isAfterLast()) {
|
||||
* if (mCanceled) {
|
||||
* // Assume a user may cancel this operation during the export.
|
||||
* return;
|
||||
* }
|
||||
* if (!composer.createOneEntry()) {
|
||||
* // Do something handling the error situation.
|
||||
* return;
|
||||
* }
|
||||
* }
|
||||
* } finally {
|
||||
* if (composer != null) {
|
||||
* composer.terminate();
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Users have to manually take care of memory efficiency. Even one vCard may contain
|
||||
* image of non-trivial size for mobile devices.
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link VCardBuilder} is used to build each vCard.
|
||||
* </p>
|
||||
*/
|
||||
public class VCardComposer {
|
||||
private static final String LOG_TAG = "VCardComposer";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
public static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO =
|
||||
"Failed to get database information";
|
||||
|
||||
public static final String FAILURE_REASON_NO_ENTRY =
|
||||
"There's no exportable in the database";
|
||||
|
||||
public static final String FAILURE_REASON_NOT_INITIALIZED =
|
||||
"The vCard composer object is not correctly initialized";
|
||||
|
||||
/** Should be visible only from developers... (no need to translate, hopefully) */
|
||||
public static final String FAILURE_REASON_UNSUPPORTED_URI =
|
||||
"The Uri vCard composer received is not supported by the composer.";
|
||||
|
||||
public static final String NO_ERROR = "No error";
|
||||
|
||||
// Strictly speaking, "Shift_JIS" is the most appropriate, but we use upper version here,
|
||||
// since usual vCard devices for Japanese devices already use it.
|
||||
private static final String SHIFT_JIS = "SHIFT_JIS";
|
||||
private static final String UTF_8 = "UTF-8";
|
||||
|
||||
private static final Map<Integer, String> sImMap;
|
||||
|
||||
static {
|
||||
sImMap = new HashMap<Integer, String>();
|
||||
sImMap.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
|
||||
sImMap.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
|
||||
sImMap.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
|
||||
sImMap.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
|
||||
sImMap.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
|
||||
sImMap.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
|
||||
// We don't add Google talk here since it has to be handled separately.
|
||||
}
|
||||
|
||||
private final int mVCardType;
|
||||
private final ContentResolver mContentResolver;
|
||||
|
||||
private final boolean mIsDoCoMo;
|
||||
/**
|
||||
* Used only when {@link #mIsDoCoMo} is true. Set to true when the first vCard for DoCoMo
|
||||
* vCard is emitted.
|
||||
*/
|
||||
private boolean mFirstVCardEmittedInDoCoMoCase;
|
||||
|
||||
private Cursor mCursor;
|
||||
private EntityIterator mEntityIterator;
|
||||
private Method mGetEntityIteratorMethod;
|
||||
private boolean mCursorSuppliedFromOutside;
|
||||
private int mIdColumn;
|
||||
private Uri mContentUriForRawContactsEntity;
|
||||
|
||||
private final String mCharset;
|
||||
|
||||
private boolean mInitDone;
|
||||
private String mErrorReason = NO_ERROR;
|
||||
|
||||
/**
|
||||
* Set to false when one of {@link #init()} variants is called, and set to true when
|
||||
* {@link #terminate()} is called. Initially set to true.
|
||||
*/
|
||||
private boolean mTerminateCalled = true;
|
||||
|
||||
private RawContactEntitlesInfoCallback mRawContactEntitlesInfoCallback;
|
||||
|
||||
private static final String[] sContactsProjection = new String[] {
|
||||
Contacts._ID,
|
||||
};
|
||||
|
||||
public VCardComposer(Context context) {
|
||||
this(context, VCardConfig.VCARD_TYPE_DEFAULT, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* The variant which sets charset to null and sets careHandlerErrors to true.
|
||||
*/
|
||||
public VCardComposer(Context context, int vcardType) {
|
||||
this(context, vcardType, null, true);
|
||||
}
|
||||
|
||||
public VCardComposer(Context context, int vcardType, String charset) {
|
||||
this(context, vcardType, charset, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* The variant which sets charset to null.
|
||||
*/
|
||||
public VCardComposer(final Context context, final int vcardType,
|
||||
final boolean careHandlerErrors) {
|
||||
this(context, vcardType, null, careHandlerErrors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs for supporting call log entry vCard composing.
|
||||
*
|
||||
* @param context Context to be used during the composition.
|
||||
* @param vcardType The type of vCard, typically available via {@link VCardConfig}.
|
||||
* @param charset The charset to be used. Use null when you don't need the charset.
|
||||
* @param careHandlerErrors If true, This object returns false everytime
|
||||
*/
|
||||
public VCardComposer(final Context context, final int vcardType, String charset,
|
||||
final boolean careHandlerErrors) {
|
||||
this(context, context.getContentResolver(), vcardType, charset, careHandlerErrors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Just for testing for now.
|
||||
* @param resolver {@link ContentResolver} which used by this object.
|
||||
* @hide
|
||||
*/
|
||||
public VCardComposer(final Context context, ContentResolver resolver,
|
||||
final int vcardType, String charset, final boolean careHandlerErrors) {
|
||||
// Not used right now
|
||||
// mContext = context;
|
||||
mVCardType = vcardType;
|
||||
mContentResolver = resolver;
|
||||
|
||||
mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
|
||||
|
||||
charset = (TextUtils.isEmpty(charset) ? VCardConfig.DEFAULT_EXPORT_CHARSET : charset);
|
||||
final boolean shouldAppendCharsetParam = !(
|
||||
VCardConfig.isVersion30(vcardType) && UTF_8.equalsIgnoreCase(charset));
|
||||
|
||||
if (mIsDoCoMo || shouldAppendCharsetParam) {
|
||||
if (SHIFT_JIS.equalsIgnoreCase(charset)) {
|
||||
mCharset = charset;
|
||||
} else {
|
||||
/* Log.w(LOG_TAG,
|
||||
"The charset \"" + charset + "\" is used while "
|
||||
+ SHIFT_JIS + " is needed to be used."); */
|
||||
if (TextUtils.isEmpty(charset)) {
|
||||
mCharset = SHIFT_JIS;
|
||||
} else {
|
||||
mCharset = charset;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (TextUtils.isEmpty(charset)) {
|
||||
mCharset = UTF_8;
|
||||
} else {
|
||||
mCharset = charset;
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(LOG_TAG, "Use the charset \"" + mCharset + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this object using default {@link Contacts#CONTENT_URI}.
|
||||
*
|
||||
* You can call this method or a variant of this method just once. In other words, you cannot
|
||||
* reuse this object.
|
||||
*
|
||||
* @return Returns true when initialization is successful and all the other
|
||||
* methods are available. Returns false otherwise.
|
||||
*/
|
||||
public boolean init() {
|
||||
return init(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special variant of init(), which accepts a Uri for obtaining {@link RawContactsEntity} from
|
||||
* {@link ContentResolver} with {@link Contacts#_ID}.
|
||||
* <code>
|
||||
* String selection = Data.CONTACT_ID + "=?";
|
||||
* String[] selectionArgs = new String[] {contactId};
|
||||
* Cursor cursor = mContentResolver.query(
|
||||
* contentUriForRawContactsEntity, null, selection, selectionArgs, null)
|
||||
* </code>
|
||||
*
|
||||
* You can call this method or a variant of this method just once. In other words, you cannot
|
||||
* reuse this object.
|
||||
*
|
||||
* @deprecated Use {@link #init(Uri, String[], String, String[], String, Uri)} if you really
|
||||
* need to change the default Uri.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean initWithRawContactsEntityUri(Uri contentUriForRawContactsEntity) {
|
||||
return init(Contacts.CONTENT_URI, sContactsProjection, null, null, null,
|
||||
contentUriForRawContactsEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this object using default {@link Contacts#CONTENT_URI} and given selection
|
||||
* arguments.
|
||||
*/
|
||||
public boolean init(final String selection, final String[] selectionArgs) {
|
||||
return init(Contacts.CONTENT_URI, sContactsProjection, selection, selectionArgs,
|
||||
null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this is unstable interface, may be deleted in the future.
|
||||
*/
|
||||
public boolean init(final Uri contentUri, final String selection,
|
||||
final String[] selectionArgs, final String sortOrder) {
|
||||
return init(contentUri, sContactsProjection, selection, selectionArgs, sortOrder, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentUri Uri for obtaining the list of contactId. Used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param selection selection used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param selectionArgs selectionArgs used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param sortOrder sortOrder used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param contentUriForRawContactsEntity Uri for obtaining entries relevant to each
|
||||
* contactId.
|
||||
* Note that this is an unstable interface, may be deleted in the future.
|
||||
*/
|
||||
public boolean init(final Uri contentUri, final String selection,
|
||||
final String[] selectionArgs, final String sortOrder,
|
||||
final Uri contentUriForRawContactsEntity) {
|
||||
return init(contentUri, sContactsProjection, selection, selectionArgs, sortOrder,
|
||||
contentUriForRawContactsEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* A variant of init(). Currently just for testing. Use other variants for init().
|
||||
*
|
||||
* First we'll create {@link Cursor} for the list of contactId.
|
||||
*
|
||||
* <code>
|
||||
* Cursor cursorForId = mContentResolver.query(
|
||||
* contentUri, projection, selection, selectionArgs, sortOrder);
|
||||
* </code>
|
||||
*
|
||||
* After that, we'll obtain data for each contactId in the list.
|
||||
*
|
||||
* <code>
|
||||
* Cursor cursorForContent = mContentResolver.query(
|
||||
* contentUriForRawContactsEntity, null,
|
||||
* Data.CONTACT_ID + "=?", new String[] {contactId}, null)
|
||||
* </code>
|
||||
*
|
||||
* {@link #createOneEntry()} or its variants let the caller obtain each entry from
|
||||
* <code>cursorForContent</code> above.
|
||||
*
|
||||
* @param contentUri Uri for obtaining the list of contactId. Used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param projection projection used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param selection selection used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param selectionArgs selectionArgs used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param sortOrder sortOrder used with
|
||||
* {@link ContentResolver#query(Uri, String[], String, String[], String)}
|
||||
* @param contentUriForRawContactsEntity Uri for obtaining entries relevant to each
|
||||
* contactId.
|
||||
* @return true when successful
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean init(final Uri contentUri, final String[] projection,
|
||||
final String selection, final String[] selectionArgs,
|
||||
final String sortOrder, Uri contentUriForRawContactsEntity) {
|
||||
if (!ContactsContract.AUTHORITY.equals(contentUri.getAuthority())) {
|
||||
if (DEBUG) Log.d(LOG_TAG, "Unexpected contentUri: " + contentUri);
|
||||
mErrorReason = FAILURE_REASON_UNSUPPORTED_URI;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initInterFirstPart(contentUriForRawContactsEntity)) {
|
||||
return false;
|
||||
}
|
||||
if (!initInterCursorCreationPart(contentUri, projection, selection, selectionArgs,
|
||||
sortOrder)) {
|
||||
return false;
|
||||
}
|
||||
if (!initInterMainPart()) {
|
||||
return false;
|
||||
}
|
||||
initEntityIterator();
|
||||
|
||||
return initInterLastPart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just for testing for now. Do not use.
|
||||
* Execute before init.
|
||||
* @hide
|
||||
*/
|
||||
public void setGetEntityIteratorMethod(Method getEntityIteratorMethod) {
|
||||
mGetEntityIteratorMethod = getEntityIteratorMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just for testing for now. Do not use.
|
||||
* @hide
|
||||
*/
|
||||
public boolean init(Cursor cursor) {
|
||||
return initWithCallback(cursor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cursor Cursor that used to get contact id
|
||||
* @param rawContactEntitlesInfoCallback Callback that return RawContactEntitlesInfo
|
||||
* Note that this is an unstable interface, may be deleted in the future.
|
||||
*
|
||||
* @return true when successful
|
||||
*/
|
||||
public boolean initWithCallback(Cursor cursor,
|
||||
RawContactEntitlesInfoCallback rawContactEntitlesInfoCallback) {
|
||||
if (!initInterFirstPart(null)) {
|
||||
return false;
|
||||
}
|
||||
mCursorSuppliedFromOutside = true;
|
||||
mCursor = cursor;
|
||||
mRawContactEntitlesInfoCallback = rawContactEntitlesInfoCallback;
|
||||
if (!initInterMainPart()) {
|
||||
return false;
|
||||
}
|
||||
initEntityIterator();
|
||||
return initInterLastPart();
|
||||
}
|
||||
|
||||
private boolean initInterFirstPart(Uri contentUriForRawContactsEntity) {
|
||||
mContentUriForRawContactsEntity =
|
||||
(contentUriForRawContactsEntity != null ? contentUriForRawContactsEntity :
|
||||
RawContactsEntity.CONTENT_URI);
|
||||
if (mInitDone) {
|
||||
Log.e(LOG_TAG, "init() is already called");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean initInterCursorCreationPart(
|
||||
final Uri contentUri, final String[] projection,
|
||||
final String selection, final String[] selectionArgs, final String sortOrder) {
|
||||
mCursorSuppliedFromOutside = false;
|
||||
mCursor = mContentResolver.query(
|
||||
contentUri, projection, selection, selectionArgs, sortOrder);
|
||||
if (mCursor == null) {
|
||||
Log.e(LOG_TAG, String.format("Cursor became null unexpectedly"));
|
||||
mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean initInterMainPart() {
|
||||
if (mCursor.getCount() == 0 || !mCursor.moveToFirst()) {
|
||||
if (DEBUG) {
|
||||
Log.d(LOG_TAG,
|
||||
String.format("mCursor has an error (getCount: %d): ", mCursor.getCount()));
|
||||
}
|
||||
mErrorReason = FAILURE_REASON_NO_ENTRY;
|
||||
closeCursorIfAppropriate();
|
||||
return false;
|
||||
}
|
||||
mIdColumn = mCursor.getColumnIndex(Data.CONTACT_ID);
|
||||
if (mIdColumn < 0) {
|
||||
mIdColumn = mCursor.getColumnIndex(Contacts._ID);
|
||||
}
|
||||
return mIdColumn >= 0;
|
||||
}
|
||||
|
||||
// Testing with 500 Contacts IDs, the export time using an EntityIterator containing all
|
||||
// Contacts IDs is approximately 120ms (each EntityIterator containing one Contacts ID takes
|
||||
// about 700ms).
|
||||
// Initializing an EntityIterator with 500 Contacts IDs takes about 10ms.
|
||||
private void initEntityIterator() {
|
||||
StringBuilder selection = new StringBuilder();
|
||||
StringBuilder contactIds = new StringBuilder();
|
||||
Uri uri = mContentUriForRawContactsEntity;
|
||||
|
||||
if (mRawContactEntitlesInfoCallback != null) {
|
||||
RawContactEntitlesInfo rawContactEntitlesInfo =
|
||||
mRawContactEntitlesInfoCallback.getRawContactEntitlesInfo(
|
||||
mCursor.getLong(mIdColumn));
|
||||
uri = rawContactEntitlesInfo.rawContactEntitlesUri;
|
||||
contactIds.append(rawContactEntitlesInfo.contactId);
|
||||
} else {
|
||||
do {
|
||||
contactIds.append(mCursor.getString(mIdColumn));
|
||||
if (!mCursor.isLast()) {
|
||||
contactIds.append(",");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (mCursor.moveToNext());
|
||||
// There are some callers that assume that the cursor is at its first position after
|
||||
// init.
|
||||
// See b/402311014
|
||||
mCursor.moveToFirst();
|
||||
}
|
||||
|
||||
selection.append(Data.CONTACT_ID).append(" IN (");
|
||||
selection.append(contactIds);
|
||||
selection.append(")");
|
||||
|
||||
if (mGetEntityIteratorMethod != null) {
|
||||
// Please note that this code is executed by unit tests only
|
||||
try {
|
||||
mEntityIterator = (EntityIterator) mGetEntityIteratorMethod.invoke(null,
|
||||
mContentResolver, uri, selection.toString(), null, null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(LOG_TAG, "IllegalArgumentException has been thrown: " +
|
||||
e.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(LOG_TAG, "IllegalAccessException has been thrown: " +
|
||||
e.getMessage());
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.e(LOG_TAG, "InvocationTargetException has been thrown: ", e);
|
||||
throw new RuntimeException("InvocationTargetException has been thrown");
|
||||
}
|
||||
} else {
|
||||
mEntityIterator = RawContacts
|
||||
.newEntityIterator(mContentResolver.query(uri, null,
|
||||
selection.toString(), null, Data.CONTACT_ID));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean initInterLastPart() {
|
||||
mInitDone = true;
|
||||
mTerminateCalled = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a vCard string.
|
||||
*/
|
||||
public String createOneEntry() {
|
||||
if (!mInitDone) {
|
||||
Log.w(LOG_TAG, "This object is not ready yet.");
|
||||
return "";
|
||||
}
|
||||
|
||||
if (mIsDoCoMo && !mFirstVCardEmittedInDoCoMoCase) {
|
||||
mFirstVCardEmittedInDoCoMoCase = true;
|
||||
// Previously we needed to emit empty data for this specific case, but actually
|
||||
// this doesn't work now, as resolver doesn't return any data with "-1" contactId.
|
||||
// TODO: re-introduce or remove this logic. Needs to modify unit test when we
|
||||
// re-introduce the logic.
|
||||
// return createOneEntryInternal("-1", getEntityIteratorMethod);
|
||||
}
|
||||
|
||||
return createOneEntryInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that store rawContactEntitlesUri and contactId
|
||||
*/
|
||||
public static class RawContactEntitlesInfo {
|
||||
public final Uri rawContactEntitlesUri;
|
||||
public final long contactId;
|
||||
public RawContactEntitlesInfo(Uri rawContactEntitlesUri, long contactId) {
|
||||
this.rawContactEntitlesUri = rawContactEntitlesUri;
|
||||
this.contactId = contactId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for getting raw contact entitles info
|
||||
*/
|
||||
public interface RawContactEntitlesInfoCallback {
|
||||
/**
|
||||
* Callback to get RawContactEntitlesInfo from contact id
|
||||
*
|
||||
* @param contactId Contact id that you want to process.
|
||||
* @return RawContactEntitlesInfo that ready to process.
|
||||
*/
|
||||
RawContactEntitlesInfo getRawContactEntitlesInfo(long contactId);
|
||||
}
|
||||
|
||||
private String createOneEntryInternal() {
|
||||
if (!mEntityIterator.hasNext()) {
|
||||
Log.w(LOG_TAG, "EntityIterator#hasNext() returned false");
|
||||
return "";
|
||||
}
|
||||
final Map<String, List<ContentValues>> contentValuesListMap =
|
||||
new HashMap<String, List<ContentValues>>();
|
||||
Entity entity = mEntityIterator.next();
|
||||
for (NamedContentValues namedContentValues : entity.getSubValues()) {
|
||||
ContentValues contentValues = namedContentValues.values;
|
||||
String key = contentValues.getAsString(Data.MIMETYPE);
|
||||
if (key != null) {
|
||||
List<ContentValues> contentValuesList = contentValuesListMap.get(key);
|
||||
if (contentValuesList == null) {
|
||||
contentValuesList = new ArrayList<ContentValues>();
|
||||
contentValuesListMap.put(key, contentValuesList);
|
||||
}
|
||||
contentValuesList.add(contentValues);
|
||||
}
|
||||
}
|
||||
|
||||
return buildVCard(contentValuesListMap);
|
||||
}
|
||||
|
||||
private VCardPhoneNumberTranslationCallback mPhoneTranslationCallback;
|
||||
/**
|
||||
* <p>
|
||||
* Set a callback for phone number formatting. It will be called every time when this object
|
||||
* receives a phone number for printing.
|
||||
* </p>
|
||||
* <p>
|
||||
* When this is set {@link VCardConfig#FLAG_REFRAIN_PHONE_NUMBER_FORMATTING} will be ignored
|
||||
* and the callback should be responsible for everything about phone number formatting.
|
||||
* </p>
|
||||
* <p>
|
||||
* Caution: This interface will change. Please don't use without any strong reason.
|
||||
* </p>
|
||||
*/
|
||||
public void setPhoneNumberTranslationCallback(VCardPhoneNumberTranslationCallback callback) {
|
||||
mPhoneTranslationCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns vCard using given map, whose key is CONTENT_ITEM_TYPE defined in
|
||||
* {ContactsContract}. Developers can override this method to customize the output.
|
||||
*/
|
||||
public String buildVCard(final Map<String, List<ContentValues>> contentValuesListMap) {
|
||||
if (contentValuesListMap == null) {
|
||||
Log.e(LOG_TAG, "The given map is null. Ignore and return empty String");
|
||||
return "";
|
||||
} else {
|
||||
final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
|
||||
builder.appendNameProperties(contentValuesListMap.get(
|
||||
StructuredName.CONTENT_ITEM_TYPE))
|
||||
.appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE),
|
||||
mPhoneTranslationCallback)
|
||||
.appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE))
|
||||
.appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
|
||||
.appendSipAddresses(contentValuesListMap.get(SipAddress.CONTENT_ITEM_TYPE));
|
||||
|
||||
if ((mVCardType & VCardConfig.FLAG_REFRAIN_NICKNAME_EXPORT) == 0) {
|
||||
builder.appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE));
|
||||
}
|
||||
if ((mVCardType & VCardConfig.FLAG_REFRAIN_EMAIL_EXPORT) == 0) {
|
||||
builder.appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE));
|
||||
}
|
||||
if ((mVCardType & VCardConfig.FLAG_REFRAIN_ADDRESS_EXPORT) == 0) {
|
||||
builder.appendPostals(contentValuesListMap.get(
|
||||
StructuredPostal.CONTENT_ITEM_TYPE));
|
||||
}
|
||||
if ((mVCardType & VCardConfig.FLAG_REFRAIN_ORGANIZATION_EXPORT) == 0) {
|
||||
builder.appendOrganizations(contentValuesListMap.get(
|
||||
Organization.CONTENT_ITEM_TYPE));
|
||||
}
|
||||
if ((mVCardType & VCardConfig.FLAG_REFRAIN_WEBSITES_EXPORT) == 0) {
|
||||
builder.appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE));
|
||||
}
|
||||
if ((mVCardType & VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT) == 0) {
|
||||
builder.appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE));
|
||||
}
|
||||
if ((mVCardType & VCardConfig.FLAG_REFRAIN_NOTES_EXPORT) == 0) {
|
||||
builder.appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE));
|
||||
}
|
||||
if ((mVCardType & VCardConfig.FLAG_REFRAIN_EVENTS_EXPORT) == 0) {
|
||||
builder.appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
closeCursorIfAppropriate();
|
||||
mTerminateCalled = true;
|
||||
}
|
||||
|
||||
private void closeCursorIfAppropriate() {
|
||||
if (!mCursorSuppliedFromOutside && mCursor != null) {
|
||||
try {
|
||||
mCursor.close();
|
||||
} catch (SQLiteException e) {
|
||||
Log.e(LOG_TAG, "SQLiteException on Cursor#close(): " + e.getMessage());
|
||||
}
|
||||
mCursor = null;
|
||||
}
|
||||
if (mEntityIterator != null) {
|
||||
try{
|
||||
mEntityIterator.close();
|
||||
} catch (SQLiteException e) {
|
||||
Log.e(LOG_TAG, "SQLiteException on EntityIterator#close(): " + e.getMessage());
|
||||
}
|
||||
mEntityIterator = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (!mTerminateCalled) {
|
||||
Log.e(LOG_TAG, "finalized() is called before terminate() being called");
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the number of available entities. The return value is undefined
|
||||
* when this object is not ready yet (typically when {{@link #init()} is not called
|
||||
* or when {@link #terminate()} is already called).
|
||||
*/
|
||||
public int getCount() {
|
||||
if (mCursor == null) {
|
||||
Log.w(LOG_TAG, "This object is not ready yet.");
|
||||
return 0;
|
||||
}
|
||||
return mCursor.getCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true when there's no entity to be built. The return value is undefined
|
||||
* when this object is not ready yet.
|
||||
*/
|
||||
public boolean isAfterLast() {
|
||||
if (mEntityIterator == null) {
|
||||
Log.w(LOG_TAG, "This object is not ready yet.");
|
||||
return false;
|
||||
}
|
||||
return !mEntityIterator.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the error reason.
|
||||
*/
|
||||
public String getErrorReason() {
|
||||
return mErrorReason;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The class representing VCard related configurations. Useful static methods are not in this class
|
||||
* but in VCardUtils.
|
||||
*/
|
||||
public class VCardConfig {
|
||||
private static final String LOG_TAG = VCardConstants.LOG_TAG;
|
||||
|
||||
/* package */ static final int LOG_LEVEL_NONE = 0;
|
||||
/* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
|
||||
/* package */ static final int LOG_LEVEL_SHOW_WARNING = 0x2;
|
||||
/* package */ static final int LOG_LEVEL_VERBOSE =
|
||||
LOG_LEVEL_PERFORMANCE_MEASUREMENT | LOG_LEVEL_SHOW_WARNING;
|
||||
|
||||
/* package */ static final int LOG_LEVEL = LOG_LEVEL_NONE;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The charset used during import.
|
||||
* </p>
|
||||
* <p>
|
||||
* We cannot determine which charset should be used to interpret lines in vCard,
|
||||
* while Java requires us to specify it when InputStream is used.
|
||||
* We need to rely on the mechanism due to some performance reason.
|
||||
* </p>
|
||||
* <p>
|
||||
* In order to avoid "misinterpretation" of charset and lose any data in vCard,
|
||||
* "ISO-8859-1" is first used for reading the stream.
|
||||
* When a charset is specified in a property (with "CHARSET=..." parameter),
|
||||
* the string is decoded to raw bytes and encoded into the specific charset,
|
||||
* </p>
|
||||
* <p>
|
||||
* Unicode specification there's a one to one mapping between each byte in ISO-8859-1
|
||||
* and a codepoint, and Java specification requires runtime must have the charset.
|
||||
* Thus, ISO-8859-1 is one effective mapping for intermediate mapping.
|
||||
* </p>
|
||||
*/
|
||||
public static final String DEFAULT_INTERMEDIATE_CHARSET = "ISO-8859-1";
|
||||
|
||||
/**
|
||||
* The charset used when there's no information affbout what charset should be used to
|
||||
* encode the binary given from vCard.
|
||||
*/
|
||||
public static final String DEFAULT_IMPORT_CHARSET = "UTF-8";
|
||||
public static final String DEFAULT_EXPORT_CHARSET = "UTF-8";
|
||||
|
||||
/**
|
||||
* Do not use statically like "version == VERSION_V21"
|
||||
*/
|
||||
public static final int VERSION_21 = 0;
|
||||
public static final int VERSION_30 = 1;
|
||||
public static final int VERSION_40 = 2;
|
||||
public static final int VERSION_MASK = 3;
|
||||
|
||||
public static final int NAME_ORDER_DEFAULT = 0;
|
||||
public static final int NAME_ORDER_EUROPE = 0x4;
|
||||
public static final int NAME_ORDER_JAPANESE = 0x8;
|
||||
private static final int NAME_ORDER_MASK = 0xC;
|
||||
|
||||
// 0x10 is reserved for safety
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The flag indicating the vCard composer will add some "X-" properties used only in Android
|
||||
* when the formal vCard specification does not have appropriate fields for that data.
|
||||
* </p>
|
||||
* <p>
|
||||
* For example, Android accepts nickname information while vCard 2.1 does not.
|
||||
* When this flag is on, vCard composer emits alternative "X-" property (like "X-NICKNAME")
|
||||
* instead of just dropping it.
|
||||
* </p>
|
||||
* <p>
|
||||
* vCard parser code automatically parses the field emitted even when this flag is off.
|
||||
* </p>
|
||||
*/
|
||||
private static final int FLAG_USE_ANDROID_PROPERTY = 0x80000000;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The flag indicating the vCard composer will add some "X-" properties seen in the
|
||||
* vCard data emitted by the other softwares/devices when the formal vCard specification
|
||||
* does not have appropriate field(s) for that data.
|
||||
* </p>
|
||||
* <p>
|
||||
* One example is X-PHONETIC-FIRST-NAME/X-PHONETIC-MIDDLE-NAME/X-PHONETIC-LAST-NAME, which are
|
||||
* for phonetic name (how the name is pronounced), seen in the vCard emitted by some other
|
||||
* non-Android devices/softwares. We chose to enable the vCard composer to use those
|
||||
* defact properties since they are also useful for Android devices.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note for developers: only "X-" properties should be added with this flag. vCard 2.1/3.0
|
||||
* allows any kind of "X-" properties but does not allow non-"X-" properties (except IANA tokens
|
||||
* in vCard 3.0). Some external parsers may get confused with non-valid, non-"X-" properties.
|
||||
* </p>
|
||||
*/
|
||||
private static final int FLAG_USE_DEFACT_PROPERTY = 0x40000000;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The flag indicating some specific dialect seen in vCard of DoCoMo (one of Japanese
|
||||
* mobile careers) should be used. This flag does not include any other information like
|
||||
* that "the vCard is for Japanese". So it is "possible" that "the vCard should have DoCoMo's
|
||||
* dialect but the name order should be European", but it is not recommended.
|
||||
* </p>
|
||||
*/
|
||||
private static final int FLAG_DOCOMO = 0x20000000;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The flag indicating the vCard composer does "NOT" use Quoted-Printable toward "primary"
|
||||
* properties even though it is required by vCard 2.1 (QP is prohibited in vCard 3.0).
|
||||
* </p>
|
||||
* <p>
|
||||
* We actually cannot define what is the "primary" property. Note that this is NOT defined
|
||||
* in vCard specification either. Also be aware that it is NOT related to "primary" notion
|
||||
* used in {@link android.provider.ContactsContract}.
|
||||
* This notion is just for vCard composition in Android.
|
||||
* </p>
|
||||
* <p>
|
||||
* We added this Android-specific notion since some (incomplete) vCard exporters for vCard 2.1
|
||||
* do NOT use Quoted-Printable encoding toward some properties related names like "N", "FN", etc.
|
||||
* even when their values contain non-ascii or/and CR/LF, while they use the encoding in the
|
||||
* other properties like "ADR", "ORG", etc.
|
||||
* <p>
|
||||
* We are afraid of the case where some vCard importer also forget handling QP presuming QP is
|
||||
* not used in such fields.
|
||||
* </p>
|
||||
* <p>
|
||||
* This flag is useful when some target importer you are going to focus on does not accept
|
||||
* such properties with Quoted-Printable encoding.
|
||||
* </p>
|
||||
* <p>
|
||||
* Again, we should not use this flag at all for complying vCard 2.1 spec.
|
||||
* </p>
|
||||
* <p>
|
||||
* In vCard 3.0, Quoted-Printable is explicitly "prohibitted", so we don't need to care this
|
||||
* kind of problem (hopefully).
|
||||
* </p>
|
||||
* @hide
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_QP_TO_NAME_PROPERTIES = 0x10000000;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The flag indicating that phonetic name related fields must be converted to
|
||||
* appropriate form. Note that "appropriate" is not defined in any vCard specification.
|
||||
* This is Android-specific.
|
||||
* </p>
|
||||
* <p>
|
||||
* One typical (and currently sole) example where we need this flag is the time when
|
||||
* we need to emit Japanese phonetic names into vCard entries. The property values
|
||||
* should be encoded into half-width katakana when the target importer is Japanese mobile
|
||||
* phones', which are probably not able to parse full-width hiragana/katakana for
|
||||
* historical reasons, while the vCard importers embedded to softwares for PC should be
|
||||
* able to parse them as we expect.
|
||||
* </p>
|
||||
*/
|
||||
public static final int FLAG_CONVERT_PHONETIC_NAME_STRINGS = 0x08000000;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The flag indicating the vCard composer "for 2.1" emits "TYPE=" string toward TYPE params
|
||||
* every time possible. The default behavior does not emit it and is valid in the spec.
|
||||
* In vCrad 3.0, this flag is unnecessary, since "TYPE=" is MUST in vCard 3.0 specification.
|
||||
* </p>
|
||||
* <p>
|
||||
* Detail:
|
||||
* How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0.
|
||||
* </p>
|
||||
* <p>
|
||||
* e.g.
|
||||
* </p>
|
||||
* <ol>
|
||||
* <li>Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."</li>
|
||||
* <li>Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."</li>
|
||||
* <li>Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* If you are targeting to the importer which cannot accept TYPE params without "TYPE="
|
||||
* strings (which should be rare though), please use this flag.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example usage:
|
||||
* <pre class="prettyprint">int type = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);</pre>
|
||||
* </p>
|
||||
*/
|
||||
public static final int FLAG_APPEND_TYPE_PARAM = 0x04000000;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The flag indicating the vCard composer does touch nothing toward phone number Strings
|
||||
* but leave it as is.
|
||||
* </p>
|
||||
* <p>
|
||||
* The vCard specifications mention nothing toward phone numbers, while some devices
|
||||
* do (wrongly, but with innevitable reasons).
|
||||
* For example, there's a possibility Japanese mobile phones are expected to have
|
||||
* just numbers, hypens, plus, etc. but not usual alphabets, while US mobile phones
|
||||
* should get such characters. To make exported vCard simple for external parsers,
|
||||
* we have used {@link PhoneNumberUtils#formatNumber(String)} during export, and
|
||||
* removed unnecessary characters inside the number (e.g. "111-222-3333 (Miami)"
|
||||
* becomes "111-222-3333").
|
||||
* Unfortunate side effect of that use was some control characters used in the other
|
||||
* areas may be badly affected by the formatting.
|
||||
* </p>
|
||||
* <p>
|
||||
* This flag disables that formatting, affecting both importer and exporter.
|
||||
* If the user is aware of some side effects due to the implicit formatting, use this flag.
|
||||
* </p>
|
||||
* <p>
|
||||
* Caution: this flag will be removed in the future, replaced by some richer functionality.
|
||||
* </p>
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_PHONE_NUMBER_FORMATTING = 0x02000000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain image export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_IMAGE_EXPORT = 0x00800000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain events export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_EVENTS_EXPORT = 0x00400000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain addess export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_ADDRESS_EXPORT = 0x00200000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain email export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_EMAIL_EXPORT = 0x00100000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain organization export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_ORGANIZATION_EXPORT = 0x00080000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain notes export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_NOTES_EXPORT = 0x00040000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain phonetic name export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_PHONETIC_NAME_EXPORT = 0x00020000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain websites export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_WEBSITES_EXPORT = 0x00010000;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The flag asking exporter to refrain nickname export.
|
||||
* </P>
|
||||
* @hide will be deleted in the near future.
|
||||
*/
|
||||
public static final int FLAG_REFRAIN_NICKNAME_EXPORT = 0x00008000;
|
||||
|
||||
//// The followings are VCard types available from importer/exporter. ////
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The type indicating nothing. Used by {@link VCardSourceDetector} when it
|
||||
* was not able to guess the exact vCard type.
|
||||
* </p>
|
||||
*/
|
||||
public static final int VCARD_TYPE_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generic vCard format with the vCard 2.1. When composing a vCard entry,
|
||||
* the US convension will be used toward formatting some values.
|
||||
* </p>
|
||||
* <p>
|
||||
* e.g. The order of the display name would be "Prefix Given Middle Family Suffix",
|
||||
* while it should be "Prefix Family Middle Given Suffix" in Japan for example.
|
||||
* </p>
|
||||
* <p>
|
||||
* Uses UTF-8 for the charset as a charset for exporting. Note that old vCard importer
|
||||
* outside Android cannot accept it since vCard 2.1 specifically does not allow
|
||||
* that charset, while we need to use it to support various languages around the world.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you want to use alternative charset, you should notify the charset to the other
|
||||
* compontent to be used.
|
||||
* </p>
|
||||
*/
|
||||
public static final int VCARD_TYPE_V21_GENERIC =
|
||||
(VERSION_21 | NAME_ORDER_DEFAULT | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static String VCARD_TYPE_V21_GENERIC_STR = "v21_generic";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* General vCard format with the version 3.0. Uses UTF-8 for the charset.
|
||||
* </p>
|
||||
* <p>
|
||||
* Not fully ready yet. Use with caution when you use this.
|
||||
* </p>
|
||||
*/
|
||||
public static final int VCARD_TYPE_V30_GENERIC =
|
||||
(VERSION_30 | NAME_ORDER_DEFAULT | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V30_GENERIC_STR = "v30_generic";
|
||||
|
||||
/**
|
||||
* General vCard format with the version 4.0.
|
||||
* @hide vCard 4.0 is not published yet.
|
||||
*/
|
||||
public static final int VCARD_TYPE_V40_GENERIC =
|
||||
(VERSION_40 | NAME_ORDER_DEFAULT | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V40_GENERIC_STR = "v40_generic";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* General vCard format for the vCard 2.1 with some Europe convension. Uses Utf-8.
|
||||
* Currently, only name order is considered ("Prefix Middle Given Family Suffix")
|
||||
* </p>
|
||||
*/
|
||||
public static final int VCARD_TYPE_V21_EUROPE =
|
||||
(VERSION_21 | NAME_ORDER_EUROPE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V21_EUROPE_STR = "v21_europe";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* General vCard format with the version 3.0 with some Europe convension. Uses UTF-8.
|
||||
* </p>
|
||||
* <p>
|
||||
* Not ready yet. Use with caution when you use this.
|
||||
* </p>
|
||||
*/
|
||||
public static final int VCARD_TYPE_V30_EUROPE =
|
||||
(VERSION_30 | NAME_ORDER_EUROPE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset.
|
||||
* </p>
|
||||
* <p>
|
||||
* Not ready yet. Use with caution when you use this.
|
||||
* </p>
|
||||
*/
|
||||
public static final int VCARD_TYPE_V21_JAPANESE =
|
||||
(VERSION_21 | NAME_ORDER_JAPANESE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V21_JAPANESE_STR = "v21_japanese_utf8";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset.
|
||||
* </p>
|
||||
* <p>
|
||||
* Not ready yet. Use with caution when you use this.
|
||||
* </p>
|
||||
*/
|
||||
public static final int VCARD_TYPE_V30_JAPANESE =
|
||||
(VERSION_30 | NAME_ORDER_JAPANESE | FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V30_JAPANESE_STR = "v30_japanese_utf8";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The vCard 2.1 based format which (partially) considers the convention in Japanese
|
||||
* mobile phones, where phonetic names are translated to half-width katakana if
|
||||
* possible, etc. It would be better to use Shift_JIS as a charset for maximum
|
||||
* compatibility.
|
||||
* </p>
|
||||
* @hide Should not be available world wide.
|
||||
*/
|
||||
public static final int VCARD_TYPE_V21_JAPANESE_MOBILE =
|
||||
(VERSION_21 | NAME_ORDER_JAPANESE |
|
||||
FLAG_CONVERT_PHONETIC_NAME_STRINGS | FLAG_REFRAIN_QP_TO_NAME_PROPERTIES);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The vCard format used in DoCoMo, which is one of Japanese mobile phone careers.
|
||||
* </p>
|
||||
* <p>
|
||||
* Base version is vCard 2.1, but the data has several DoCoMo-specific convensions.
|
||||
* No Android-specific property nor defact property is included. The "Primary" properties
|
||||
* are NOT encoded to Quoted-Printable.
|
||||
* </p>
|
||||
* @hide Should not be available world wide.
|
||||
*/
|
||||
public static final int VCARD_TYPE_DOCOMO =
|
||||
(VCARD_TYPE_V21_JAPANESE_MOBILE | FLAG_DOCOMO);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_DOCOMO_STR = "docomo";
|
||||
|
||||
public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC;
|
||||
|
||||
private static final Map<String, Integer> sVCardTypeMap;
|
||||
private static final Set<Integer> sJapaneseMobileTypeSet;
|
||||
|
||||
static {
|
||||
sVCardTypeMap = new HashMap<String, Integer>();
|
||||
sVCardTypeMap.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC);
|
||||
sVCardTypeMap.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC);
|
||||
sVCardTypeMap.put(VCARD_TYPE_V21_EUROPE_STR, VCARD_TYPE_V21_EUROPE);
|
||||
sVCardTypeMap.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE);
|
||||
sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_STR, VCARD_TYPE_V21_JAPANESE);
|
||||
sVCardTypeMap.put(VCARD_TYPE_V30_JAPANESE_STR, VCARD_TYPE_V30_JAPANESE);
|
||||
sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_MOBILE_STR, VCARD_TYPE_V21_JAPANESE_MOBILE);
|
||||
sVCardTypeMap.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO);
|
||||
|
||||
sJapaneseMobileTypeSet = new HashSet<Integer>();
|
||||
sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE);
|
||||
sJapaneseMobileTypeSet.add(VCARD_TYPE_V30_JAPANESE);
|
||||
sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_MOBILE);
|
||||
sJapaneseMobileTypeSet.add(VCARD_TYPE_DOCOMO);
|
||||
}
|
||||
|
||||
public static int getVCardTypeFromString(final String vcardTypeString) {
|
||||
final String loweredKey = vcardTypeString.toLowerCase();
|
||||
if (sVCardTypeMap.containsKey(loweredKey)) {
|
||||
return sVCardTypeMap.get(loweredKey);
|
||||
} else if ("default".equalsIgnoreCase(vcardTypeString)) {
|
||||
return VCARD_TYPE_DEFAULT;
|
||||
} else {
|
||||
Log.e(LOG_TAG, "Unknown vCard type String: \"" + vcardTypeString + "\"");
|
||||
return VCARD_TYPE_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isVersion21(final int vcardType) {
|
||||
return (vcardType & VERSION_MASK) == VERSION_21;
|
||||
}
|
||||
|
||||
public static boolean isVersion30(final int vcardType) {
|
||||
return (vcardType & VERSION_MASK) == VERSION_30;
|
||||
}
|
||||
|
||||
public static boolean isVersion40(final int vcardType) {
|
||||
return (vcardType & VERSION_MASK) == VERSION_40;
|
||||
}
|
||||
|
||||
public static boolean shouldUseQuotedPrintable(final int vcardType) {
|
||||
return !isVersion30(vcardType);
|
||||
}
|
||||
|
||||
public static int getNameOrderType(final int vcardType) {
|
||||
return vcardType & NAME_ORDER_MASK;
|
||||
}
|
||||
|
||||
public static boolean usesAndroidSpecificProperty(final int vcardType) {
|
||||
return ((vcardType & FLAG_USE_ANDROID_PROPERTY) != 0);
|
||||
}
|
||||
|
||||
public static boolean usesDefactProperty(final int vcardType) {
|
||||
return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0);
|
||||
}
|
||||
|
||||
public static boolean showPerformanceLog() {
|
||||
return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
|
||||
}
|
||||
|
||||
public static boolean shouldRefrainQPToNameProperties(final int vcardType) {
|
||||
return (!shouldUseQuotedPrintable(vcardType) ||
|
||||
((vcardType & FLAG_REFRAIN_QP_TO_NAME_PROPERTIES) != 0));
|
||||
}
|
||||
|
||||
public static boolean appendTypeParamName(final int vcardType) {
|
||||
return (isVersion30(vcardType) || ((vcardType & FLAG_APPEND_TYPE_PARAM) != 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the device is Japanese and some Japanese convension is
|
||||
* applied to creating "formatted" something like FORMATTED_ADDRESS.
|
||||
*/
|
||||
public static boolean isJapaneseDevice(final int vcardType) {
|
||||
// TODO: Some mask will be required so that this method wrongly interpret
|
||||
// Japanese"-like" vCard type.
|
||||
// e.g. VCARD_TYPE_V21_JAPANESE_SJIS | FLAG_APPEND_TYPE_PARAMS
|
||||
return sJapaneseMobileTypeSet.contains(vcardType);
|
||||
}
|
||||
|
||||
/* package */ static boolean refrainPhoneNumberFormatting(final int vcardType) {
|
||||
return ((vcardType & FLAG_REFRAIN_PHONE_NUMBER_FORMATTING) != 0);
|
||||
}
|
||||
|
||||
public static boolean needsToConvertPhoneticString(final int vcardType) {
|
||||
return ((vcardType & FLAG_CONVERT_PHONETIC_NAME_STRINGS) != 0);
|
||||
}
|
||||
|
||||
public static boolean onlyOneNoteFieldIsAvailable(final int vcardType) {
|
||||
return vcardType == VCARD_TYPE_DOCOMO;
|
||||
}
|
||||
|
||||
public static boolean isDoCoMo(final int vcardType) {
|
||||
return ((vcardType & FLAG_DOCOMO) != 0);
|
||||
}
|
||||
|
||||
private VCardConfig() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
/**
|
||||
* Constants used in both exporter and importer code.
|
||||
*/
|
||||
public class VCardConstants {
|
||||
/* package */ static final String LOG_TAG = "vCard";
|
||||
public static final String VERSION_V21 = "2.1";
|
||||
public static final String VERSION_V30 = "3.0";
|
||||
public static final String VERSION_V40 = "4.0";
|
||||
|
||||
// Valid and supported property names.
|
||||
public static final String PROPERTY_BEGIN = "BEGIN";
|
||||
public static final String PROPERTY_VERSION = "VERSION";
|
||||
public static final String PROPERTY_N = "N";
|
||||
public static final String PROPERTY_FN = "FN";
|
||||
public static final String PROPERTY_ADR = "ADR";
|
||||
public static final String PROPERTY_EMAIL = "EMAIL";
|
||||
public static final String PROPERTY_NOTE = "NOTE";
|
||||
public static final String PROPERTY_ORG = "ORG";
|
||||
public static final String PROPERTY_SOUND = "SOUND"; // Not fully supported.
|
||||
public static final String PROPERTY_TEL = "TEL";
|
||||
public static final String PROPERTY_TITLE = "TITLE";
|
||||
public static final String PROPERTY_ROLE = "ROLE";
|
||||
public static final String PROPERTY_PHOTO = "PHOTO";
|
||||
public static final String PROPERTY_LOGO = "LOGO";
|
||||
public static final String PROPERTY_URL = "URL";
|
||||
public static final String PROPERTY_BDAY = "BDAY"; // Birthday (3.0, 4.0)
|
||||
public static final String PROPERTY_ANNIVERSARY = "ANNIVERSARY"; // Date of marriage (4.0)
|
||||
public static final String PROPERTY_NAME = "NAME"; // (3.0)
|
||||
public static final String PROPERTY_NICKNAME = "NICKNAME"; // (3.0, 4.0)
|
||||
public static final String PROPERTY_SORT_STRING = "SORT-STRING"; // (3.0, 4.0)
|
||||
public static final String PROPERTY_IMPP = "IMPP"; // RFC 4770 (vCard 3.0) and vCard 4.0
|
||||
public static final String PROPERTY_END = "END";
|
||||
|
||||
// Valid property names which are not supported (not appropriately handled) by
|
||||
// importer/exporter. Those properties will be read and discarded silently.
|
||||
public static final String PROPERTY_REV = "REV";
|
||||
public static final String PROPERTY_AGENT = "AGENT"; // (3.0)
|
||||
public static final String PROPERTY_GENDER = "GENDER"; // (4.0)
|
||||
public static final String PROPERTY_XML = "XML"; // (4.0)
|
||||
public static final String PROPERTY_FBURL = "FBURL"; // (4.0)
|
||||
public static final String PROPERTY_PRODID = "PRODID"; // (4.0)
|
||||
public static final String PROPERTY_RELATED = "RELATED"; // (4.0)
|
||||
public static final String PROPERTY_CATEGORIES = "CATEGORIES"; // (4.0)
|
||||
public static final String PROPERTY_CLIENTPIDMAP = "CLIENTPIDMAP"; // (4.0)
|
||||
public static final String PROPERTY_CALURI = "CALURI"; // (4.0)
|
||||
|
||||
|
||||
|
||||
// defact SIP property which had been used till RFC 4770.
|
||||
public static final String PROPERTY_X_SIP = "X-SIP";
|
||||
|
||||
// Available in vCard 3.0. Shoud not use when composing vCard 2.1 file.
|
||||
|
||||
// De-fact property values expressing phonetic names.
|
||||
public static final String PROPERTY_X_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME";
|
||||
public static final String PROPERTY_X_PHONETIC_MIDDLE_NAME = "X-PHONETIC-MIDDLE-NAME";
|
||||
public static final String PROPERTY_X_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME";
|
||||
|
||||
// Properties both ContactsStruct and de-fact vCard extensions
|
||||
// Shown in http://en.wikipedia.org/wiki/VCard support are defined here.
|
||||
public static final String PROPERTY_X_AIM = "X-AIM";
|
||||
public static final String PROPERTY_X_MSN = "X-MSN";
|
||||
public static final String PROPERTY_X_YAHOO = "X-YAHOO";
|
||||
public static final String PROPERTY_X_ICQ = "X-ICQ";
|
||||
public static final String PROPERTY_X_JABBER = "X-JABBER";
|
||||
public static final String PROPERTY_X_GOOGLE_TALK = "X-GOOGLE-TALK";
|
||||
public static final String PROPERTY_X_SKYPE_USERNAME = "X-SKYPE-USERNAME";
|
||||
// Properties only ContactsStruct has. We alse use this.
|
||||
public static final String PROPERTY_X_QQ = "X-QQ";
|
||||
public static final String PROPERTY_X_NETMEETING = "X-NETMEETING";
|
||||
|
||||
// Phone number for Skype, available as usual phone.
|
||||
public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
|
||||
|
||||
// Property for Android-specific fields.
|
||||
public static final String PROPERTY_X_ANDROID_CUSTOM = "X-ANDROID-CUSTOM";
|
||||
|
||||
// Properties for DoCoMo vCard.
|
||||
public static final String PROPERTY_X_CLASS = "X-CLASS";
|
||||
public static final String PROPERTY_X_REDUCTION = "X-REDUCTION";
|
||||
public static final String PROPERTY_X_NO = "X-NO";
|
||||
public static final String PROPERTY_X_DCM_HMN_MODE = "X-DCM-HMN-MODE";
|
||||
|
||||
public static final String PARAM_TYPE = "TYPE";
|
||||
|
||||
public static final String PARAM_TYPE_HOME = "HOME";
|
||||
public static final String PARAM_TYPE_WORK = "WORK";
|
||||
public static final String PARAM_TYPE_FAX = "FAX";
|
||||
public static final String PARAM_TYPE_CELL = "CELL";
|
||||
public static final String PARAM_TYPE_VOICE = "VOICE";
|
||||
public static final String PARAM_TYPE_INTERNET = "INTERNET";
|
||||
|
||||
public static final String PARAM_VALUE = "VALUE";
|
||||
public static final String PARAM_CHARSET = "CHARSET";
|
||||
public static final String PARAM_ENCODING = "ENCODING";
|
||||
|
||||
// Abbreviation of "prefered" according to vCard 2.1 specification.
|
||||
// We interpret this value as "primary" property during import/export.
|
||||
//
|
||||
// Note: Both vCard specs does not mention anything about the requirement for this parameter,
|
||||
// but there may be some vCard importer which will get confused with more than
|
||||
// one "PREF"s in one property name, while Android accepts them.
|
||||
public static final String PARAM_TYPE_PREF = "PREF";
|
||||
|
||||
// Phone type parameters valid in vCard and known to ContactsContract, but not so common.
|
||||
public static final String PARAM_TYPE_CAR = "CAR";
|
||||
public static final String PARAM_TYPE_ISDN = "ISDN";
|
||||
public static final String PARAM_TYPE_PAGER = "PAGER";
|
||||
public static final String PARAM_TYPE_TLX = "TLX"; // Telex
|
||||
|
||||
// Phone types existing in vCard 2.1 but not known to ContactsContract.
|
||||
public static final String PARAM_TYPE_MODEM = "MODEM";
|
||||
public static final String PARAM_TYPE_MSG = "MSG";
|
||||
public static final String PARAM_TYPE_BBS = "BBS";
|
||||
public static final String PARAM_TYPE_VIDEO = "VIDEO";
|
||||
|
||||
public static final String PARAM_ENCODING_7BIT = "7BIT";
|
||||
public static final String PARAM_ENCODING_8BIT = "8BIT";
|
||||
public static final String PARAM_ENCODING_QP = "QUOTED-PRINTABLE";
|
||||
public static final String PARAM_ENCODING_BASE64 = "BASE64"; // Available in vCard 2.1
|
||||
public static final String PARAM_ENCODING_B = "B"; // Available in vCard 3.0
|
||||
|
||||
// TYPE parameters for Phones, which are not formally valid in vCard (at least 2.1).
|
||||
// These types are basically encoded to "X-" parameters when composing vCard.
|
||||
// Parser passes these when "X-" is added to the parameter or not.
|
||||
public static final String PARAM_PHONE_EXTRA_TYPE_CALLBACK = "CALLBACK";
|
||||
public static final String PARAM_PHONE_EXTRA_TYPE_RADIO = "RADIO";
|
||||
public static final String PARAM_PHONE_EXTRA_TYPE_TTY_TDD = "TTY-TDD";
|
||||
public static final String PARAM_PHONE_EXTRA_TYPE_ASSISTANT = "ASSISTANT";
|
||||
// vCard composer translates this type to "WORK" + "PREF". Just for parsing.
|
||||
public static final String PARAM_PHONE_EXTRA_TYPE_COMPANY_MAIN = "COMPANY-MAIN";
|
||||
// vCard composer translates this type to "VOICE" Just for parsing.
|
||||
public static final String PARAM_PHONE_EXTRA_TYPE_OTHER = "OTHER";
|
||||
|
||||
// TYPE parameters for postal addresses.
|
||||
public static final String PARAM_ADR_TYPE_PARCEL = "PARCEL";
|
||||
public static final String PARAM_ADR_TYPE_DOM = "DOM";
|
||||
public static final String PARAM_ADR_TYPE_INTL = "INTL";
|
||||
// {@link VCardBuilder} translates this type to "X-OTHER".
|
||||
public static final String PARAM_ADR_EXTRA_TYPE_OTHER = "OTHER";
|
||||
|
||||
public static final String PARAM_LANGUAGE = "LANGUAGE";
|
||||
|
||||
// SORT-AS parameter introduced in vCard 4.0 (as of rev.13)
|
||||
public static final String PARAM_SORT_AS = "SORT-AS";
|
||||
|
||||
// TYPE parameters not officially valid but used in some vCard exporter.
|
||||
// Do not use in composer side.
|
||||
public static final String PARAM_EXTRA_TYPE_COMPANY = "COMPANY";
|
||||
|
||||
public interface ImportOnly {
|
||||
public static final String PROPERTY_X_NICKNAME = "X-NICKNAME";
|
||||
// Some device emits this "X-" parameter for expressing Google Talk,
|
||||
// which is specifically invalid but should be always properly accepted, and emitted
|
||||
// in some special case (for that device/application).
|
||||
public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
|
||||
}
|
||||
|
||||
//// Mainly for package constants.
|
||||
|
||||
// DoCoMo specific type parameter. Used with "SOUND" property, which is alternate of
|
||||
// SORT-STRING invCard 3.0.
|
||||
/* package */ static final String PARAM_TYPE_X_IRMC_N = "X-IRMC-N";
|
||||
|
||||
// Used in unit test.
|
||||
public static final int MAX_DATA_COLUMN = 15;
|
||||
|
||||
/* package */ static final int MAX_CHARACTER_NUMS_QP = 76;
|
||||
static final int MAX_CHARACTER_NUMS_BASE64_V30 = 75;
|
||||
|
||||
private VCardConstants() {
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.ContactsContract;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* {@link VCardEntryHandler} implementation which commits the entry to ContentResolver.
|
||||
* </P>
|
||||
* <P>
|
||||
* Note:<BR />
|
||||
* Each vCard may contain big photo images encoded by BASE64,
|
||||
* If we store all vCard entries in memory, OutOfMemoryError may be thrown.
|
||||
* Thus, this class push each VCard entry into ContentResolver immediately.
|
||||
* </P>
|
||||
*/
|
||||
public class VCardEntryCommitter implements VCardEntryHandler {
|
||||
public static String LOG_TAG = VCardConstants.LOG_TAG;
|
||||
|
||||
private final ContentResolver mContentResolver;
|
||||
private long mTimeToCommit;
|
||||
// Set the default maximum batch size to 20
|
||||
private int mMaxBatchSize = 20;
|
||||
private ArrayList<ContentProviderOperation> mOperationList;
|
||||
private final ArrayList<Uri> mCreatedUris = new ArrayList<Uri>();
|
||||
|
||||
public VCardEntryCommitter(ContentResolver resolver) {
|
||||
mContentResolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd() {
|
||||
if (mOperationList != null) {
|
||||
mCreatedUris.add(pushIntoContentResolver(mOperationList));
|
||||
}
|
||||
|
||||
if (VCardConfig.showPerformanceLog()) {
|
||||
Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit));
|
||||
}
|
||||
}
|
||||
|
||||
//because the max batch size is 500 defined in ContactsProvider,so we can enlarge this batch
|
||||
//size to reduce db open/close times. From testing results, we can see performance better
|
||||
//when batch size is more bigger.And also each vcardEntry may have some operation records.
|
||||
//So we can set threshold as 450, batch operations will be executed when threshold reached.
|
||||
//Testing result.
|
||||
//batch size : 100 200 300 400 450 490 20
|
||||
//consume time(10000 contacts): 178s 143s 127s 124s 119s 117s 195s
|
||||
//consume time (1000 contacts): 17.3s 13.9s 12.6s 12.2s 11.8s 11.6s 19.8s
|
||||
public void setMaxBatchSize(int batchSize) {
|
||||
mMaxBatchSize = batchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryCreated(final VCardEntry vcardEntry) {
|
||||
final long start = System.currentTimeMillis();
|
||||
mOperationList = vcardEntry.constructInsertOperations(mContentResolver, mOperationList);
|
||||
if (mOperationList != null && mOperationList.size() >= mMaxBatchSize) {
|
||||
mCreatedUris.add(pushIntoContentResolver(mOperationList));
|
||||
mOperationList = null;
|
||||
}
|
||||
mTimeToCommit += System.currentTimeMillis() - start;
|
||||
}
|
||||
|
||||
private Uri pushIntoContentResolver(ArrayList<ContentProviderOperation> operationList) {
|
||||
try {
|
||||
final ContentProviderResult[] results = mContentResolver.applyBatch(
|
||||
ContactsContract.AUTHORITY, operationList);
|
||||
|
||||
// the first result is always the raw_contact. return it's uri so
|
||||
// that it can be found later. do null checking for badly behaving
|
||||
// ContentResolvers
|
||||
return ((results == null || results.length == 0 || results[0] == null)
|
||||
? null : results[0].uri);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
||||
return null;
|
||||
} catch (OperationApplicationException e) {
|
||||
Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of created Uris. This list should not be modified by the caller as it is
|
||||
* not a clone.
|
||||
*/
|
||||
public ArrayList<Uri> getCreatedUris() {
|
||||
return mCreatedUris;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The {@link VCardInterpreter} implementation which enables {@link VCardEntryHandler} objects
|
||||
* to easily handle each vCard entry.
|
||||
* </p>
|
||||
* <p>
|
||||
* This class understand details inside vCard and translates it to {@link VCardEntry}.
|
||||
* Then the class throw it to {@link VCardEntryHandler} registered via
|
||||
* {@link #addEntryHandler(VCardEntryHandler)}, so that all those registered objects
|
||||
* are able to handle the {@link VCardEntry} object.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you want to know the detail inside vCard, it would be better to implement
|
||||
* {@link VCardInterpreter} directly, instead of relying on this class and
|
||||
* {@link VCardEntry} created by the object.
|
||||
* </p>
|
||||
*/
|
||||
public class VCardEntryConstructor implements VCardInterpreter {
|
||||
private static String LOG_TAG = VCardConstants.LOG_TAG;
|
||||
|
||||
/**
|
||||
* Represents current stack of VCardEntry. Used to support nested vCard (vCard 2.1).
|
||||
*/
|
||||
private final List<VCardEntry> mEntryStack = new ArrayList<VCardEntry>();
|
||||
private VCardEntry mCurrentEntry;
|
||||
|
||||
private final int mVCardType;
|
||||
private final Account mAccount;
|
||||
|
||||
private final List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();
|
||||
|
||||
public VCardEntryConstructor() {
|
||||
this(VCardConfig.VCARD_TYPE_V21_GENERIC, null, null);
|
||||
}
|
||||
|
||||
public VCardEntryConstructor(final int vcardType) {
|
||||
this(vcardType, null, null);
|
||||
}
|
||||
|
||||
public VCardEntryConstructor(final int vcardType, final Account account) {
|
||||
this(vcardType, account, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated targetCharset is not used anymore.
|
||||
* Use {@link #VCardEntryConstructor(int, Account)}
|
||||
*/
|
||||
@Deprecated
|
||||
public VCardEntryConstructor(final int vcardType, final Account account,
|
||||
String targetCharset) {
|
||||
mVCardType = vcardType;
|
||||
mAccount = account;
|
||||
}
|
||||
|
||||
public void addEntryHandler(VCardEntryHandler entryHandler) {
|
||||
mEntryHandlers.add(entryHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVCardStarted() {
|
||||
for (VCardEntryHandler entryHandler : mEntryHandlers) {
|
||||
entryHandler.onStart();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVCardEnded() {
|
||||
for (VCardEntryHandler entryHandler : mEntryHandlers) {
|
||||
entryHandler.onEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mCurrentEntry = null;
|
||||
mEntryStack.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryStarted() {
|
||||
mCurrentEntry = new VCardEntry(mVCardType, mAccount);
|
||||
mEntryStack.add(mCurrentEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryEnded() {
|
||||
mCurrentEntry.consolidateFields();
|
||||
for (VCardEntryHandler entryHandler : mEntryHandlers) {
|
||||
entryHandler.onEntryCreated(mCurrentEntry);
|
||||
}
|
||||
|
||||
final int size = mEntryStack.size();
|
||||
if (size > 1) {
|
||||
VCardEntry parent = mEntryStack.get(size - 2);
|
||||
parent.addChild(mCurrentEntry);
|
||||
mCurrentEntry = parent;
|
||||
} else {
|
||||
mCurrentEntry = null;
|
||||
}
|
||||
mEntryStack.remove(size - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyCreated(VCardProperty property) {
|
||||
mCurrentEntry.addProperty(property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
/**
|
||||
* The class which just counts the number of vCard entries in the specified input.
|
||||
*/
|
||||
public class VCardEntryCounter implements VCardInterpreter {
|
||||
private int mCount;
|
||||
|
||||
public int getCount() {
|
||||
return mCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVCardStarted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVCardEnded() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryStarted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryEnded() {
|
||||
mCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyCreated(VCardProperty property) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The interface called by {@link VCardEntryConstructor}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This class is useful when you don't want to know vCard data in detail. If you want to know
|
||||
* it, it would be better to consider using {@link VCardInterpreter}.
|
||||
* </p>
|
||||
*/
|
||||
public interface VCardEntryHandler {
|
||||
/**
|
||||
* Called when the parsing started.
|
||||
*/
|
||||
public void onStart();
|
||||
|
||||
/**
|
||||
* The method called when one vCard entry is created. Children come before their parent in
|
||||
* nested vCard files.
|
||||
*
|
||||
* e.g.
|
||||
* In the following vCard, the entry for "entry2" comes before one for "entry1".
|
||||
* <code>
|
||||
* BEGIN:VCARD
|
||||
* N:entry1
|
||||
* BEGIN:VCARD
|
||||
* N:entry2
|
||||
* END:VCARD
|
||||
* END:VCARD
|
||||
* </code>
|
||||
*/
|
||||
public void onEntryCreated(final VCardEntry entry);
|
||||
|
||||
/**
|
||||
* Called when the parsing ended.
|
||||
* Able to be use this method for showing performance log, etc.
|
||||
*/
|
||||
public void onEnd();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* The interface which should be implemented by the classes which have to analyze each
|
||||
* vCard entry minutely.
|
||||
* </P>
|
||||
* <P>
|
||||
* Here, there are several terms specific to vCard (and this library).
|
||||
* </P>
|
||||
* <P>
|
||||
* The term "entry" is one vCard representation in the input, which should start with "BEGIN:VCARD"
|
||||
* and end with "END:VCARD".
|
||||
* </P>
|
||||
* <P>
|
||||
* The term "property" is one line in vCard entry, which consists of "group", "property name",
|
||||
* "parameter(param) names and values", and "property values".
|
||||
* </P>
|
||||
* <P>
|
||||
* e.g. group1.propName;paramName1=paramValue1;paramName2=paramValue2;propertyValue1;propertyValue2...
|
||||
* </P>
|
||||
*/
|
||||
public interface VCardInterpreter {
|
||||
/**
|
||||
* Called when vCard interpretation started.
|
||||
*/
|
||||
void onVCardStarted();
|
||||
|
||||
/**
|
||||
* Called when vCard interpretation finished.
|
||||
*/
|
||||
void onVCardEnded();
|
||||
|
||||
/**
|
||||
* Called when parsing one vCard entry started.
|
||||
* More specifically, this method is called when "BEGIN:VCARD" is read.
|
||||
*
|
||||
* This may be called before {@link #onEntryEnded()} is called, as vCard 2.1 accepts nested
|
||||
* vCard.
|
||||
*
|
||||
* <code>
|
||||
* BEGIN:VCARD
|
||||
* BEGIN:VCARD
|
||||
* VERSION:2.1
|
||||
* N:test;;;;
|
||||
* END:VCARD
|
||||
* END:VCARD
|
||||
* </code>
|
||||
*/
|
||||
void onEntryStarted();
|
||||
|
||||
/**
|
||||
* Called when parsing one vCard entry ended.
|
||||
* More specifically, this method is called when "END:VCARD" is read.
|
||||
*/
|
||||
void onEntryEnded();
|
||||
|
||||
/**
|
||||
* Called when a property is created.
|
||||
*/
|
||||
void onPropertyCreated(VCardProperty property);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import com.android.vcard.exception.VCardException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public abstract class VCardParser {
|
||||
|
||||
/**
|
||||
* Registers one {@link VCardInterpreter} instance, which receives events along with
|
||||
* vCard parsing.
|
||||
*
|
||||
* @param interpreter
|
||||
*/
|
||||
public abstract void addInterpreter(VCardInterpreter interpreter);
|
||||
|
||||
/**
|
||||
* <p>Parses a whole InputStream as a vCard file and lets registered {@link VCardInterpreter}
|
||||
* instances handle callbacks.</p>
|
||||
*
|
||||
* <p>This method reads a whole InputStream. If you just want to parse one vCard entry inside
|
||||
* a vCard file with multiple entries, try {@link #parseOne(InputStream)}.</p>
|
||||
*
|
||||
* @param is The source to parse.
|
||||
* @throws IOException, VCardException
|
||||
*/
|
||||
public abstract void parse(InputStream is) throws IOException, VCardException;
|
||||
|
||||
/**
|
||||
* <p>Parses the first vCard entry in InputStream and lets registered {@link VCardInterpreter}
|
||||
* instances handle callbacks.</p>
|
||||
*
|
||||
* <p>This method finishes itself when the first entry ended.</p>
|
||||
*
|
||||
* <p>Note that, registered {@link VCardInterpreter} may still see multiple
|
||||
* {@link VCardInterpreter#onEntryStarted()} / {@link VCardInterpreter#onEntryEnded()} calls
|
||||
* even with this method.</p>
|
||||
*
|
||||
* <p>This happens when the first entry contains nested vCards, which is allowed in vCard 2.1.
|
||||
* See the following example.</p>
|
||||
*
|
||||
* <code>
|
||||
* BEGIN:VCARD
|
||||
* N:a
|
||||
* BEGIN:VCARD
|
||||
* N:b
|
||||
* END:VCARD
|
||||
* END:VCARD
|
||||
* </code>
|
||||
*
|
||||
* <p>With this vCard, registered interpreters will grab two
|
||||
* {@link VCardInterpreter#onEntryStarted()} and {@link VCardInterpreter#onEntryEnded()}
|
||||
* calls. Callers should handle the situation by themselves.</p>
|
||||
*
|
||||
* @param is The source to parse.
|
||||
* @throws IOException, VCardException
|
||||
*/
|
||||
public abstract void parseOne(InputStream is) throws IOException, VCardException;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #addInterpreter(VCardInterpreter)} and
|
||||
* {@link #parse(InputStream)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void parse(InputStream is, VCardInterpreter interpreter)
|
||||
throws IOException, VCardException {
|
||||
addInterpreter(interpreter);
|
||||
parse(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Cancel parsing vCard. Useful when you want to stop the parse in the other threads.
|
||||
* </p>
|
||||
* <p>
|
||||
* Actual cancel is done after parsing the current vcard.
|
||||
* </p>
|
||||
*/
|
||||
public abstract void cancel();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.vcard.exception.VCardException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Basic implementation achieving vCard 3.0 parsing.
|
||||
* </p>
|
||||
* <p>
|
||||
* This class inherits vCard 2.1 implementation since technically they are similar,
|
||||
* while specifically there's logical no relevance between them.
|
||||
* So that developers are not confused with the inheritance,
|
||||
* {@link VCardParser_V30} does not inherit {@link VCardParser_V21}, while
|
||||
* {@link VCardParserImpl_V30} inherits {@link VCardParserImpl_V21}.
|
||||
* </p>
|
||||
* @hide
|
||||
*/
|
||||
/* package */ class VCardParserImpl_V30 extends VCardParserImpl_V21 {
|
||||
private static final String LOG_TAG = VCardConstants.LOG_TAG;
|
||||
|
||||
private String mPreviousLine;
|
||||
private boolean mEmittedAgentWarning = false;
|
||||
|
||||
public VCardParserImpl_V30() {
|
||||
super();
|
||||
}
|
||||
|
||||
public VCardParserImpl_V30(int vcardType) {
|
||||
super(vcardType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVersion() {
|
||||
return VCardConfig.VERSION_30;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getVersionString() {
|
||||
return VCardConstants.VERSION_V30;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String peekLine() throws IOException {
|
||||
if (mPreviousLine != null) {
|
||||
String ret = mPreviousLine;
|
||||
return ret;
|
||||
} else {
|
||||
return mReader.peekLine();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLine() throws IOException {
|
||||
if (mPreviousLine != null) {
|
||||
String ret = mPreviousLine;
|
||||
mPreviousLine = null;
|
||||
return ret;
|
||||
} else {
|
||||
return mReader.readLine();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vCard 3.0 requires that the line with space at the beginning of the line
|
||||
* must be combined with previous line.
|
||||
*/
|
||||
@Override
|
||||
protected String getNonEmptyLine() throws IOException, VCardException {
|
||||
String line;
|
||||
StringBuilder builder = null;
|
||||
while ((line = mReader.readLine()) != null) {
|
||||
// Skip empty lines in order to accomodate implementations that
|
||||
// send line termination variations such as \r\r\n.
|
||||
if (line.length() == 0) {
|
||||
continue;
|
||||
} else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') {
|
||||
// RFC 2425 describes line continuation as \r\n followed by
|
||||
// a single ' ' or '\t' whitespace character.
|
||||
if (builder == null) {
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
if (mPreviousLine != null) {
|
||||
builder.append(mPreviousLine);
|
||||
mPreviousLine = null;
|
||||
}
|
||||
builder.append(line.substring(1));
|
||||
} else {
|
||||
if (builder != null || mPreviousLine != null) {
|
||||
break;
|
||||
}
|
||||
mPreviousLine = line;
|
||||
}
|
||||
}
|
||||
|
||||
String ret = null;
|
||||
if (builder != null) {
|
||||
ret = builder.toString();
|
||||
} else if (mPreviousLine != null) {
|
||||
ret = mPreviousLine;
|
||||
}
|
||||
mPreviousLine = line;
|
||||
if (ret == null) {
|
||||
throw new VCardException("Reached end of buffer.");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* vcard = [group "."] "BEGIN" ":" "VCARD" 1 * CRLF
|
||||
* 1 * (contentline)
|
||||
* ;A vCard object MUST include the VERSION, FN and N types.
|
||||
* [group "."] "END" ":" "VCARD" 1 * CRLF
|
||||
*/
|
||||
@Override
|
||||
protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
|
||||
// TODO: vCard 3.0 supports group.
|
||||
return super.readBeginVCard(allowGarbage);
|
||||
}
|
||||
|
||||
/**
|
||||
* vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not.
|
||||
*/
|
||||
@Override
|
||||
protected void handleParams(VCardProperty propertyData, final String params)
|
||||
throws VCardException {
|
||||
try {
|
||||
super.handleParams(propertyData, params);
|
||||
} catch (VCardException e) {
|
||||
// maybe IANA type
|
||||
String[] strArray = params.split("=", 2);
|
||||
if (strArray.length == 2) {
|
||||
handleAnyParam(propertyData, strArray[0], strArray[1]);
|
||||
} else {
|
||||
// Must not come here in the current implementation.
|
||||
throw new VCardException(
|
||||
"Unknown params value: " + params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleAnyParam(
|
||||
VCardProperty propertyData, final String paramName, final String paramValue) {
|
||||
splitAndPutParam(propertyData, paramName, paramValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleParamWithoutName(VCardProperty property, final String paramValue) {
|
||||
handleType(property, paramValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* vCard 3.0 defines
|
||||
*
|
||||
* param = param-name "=" param-value *("," param-value)
|
||||
* param-name = iana-token / x-name
|
||||
* param-value = ptext / quoted-string
|
||||
* quoted-string = DQUOTE QSAFE-CHAR DQUOTE
|
||||
* QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-ASCII
|
||||
* ; Any character except CTLs, DQUOTE
|
||||
*
|
||||
* QSAFE-CHAR must not contain DQUOTE, including escaped one (\").
|
||||
*/
|
||||
@Override
|
||||
protected void handleType(VCardProperty property, final String paramValue) {
|
||||
splitAndPutParam(property, VCardConstants.PARAM_TYPE, paramValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits parameter values into pieces in accordance with vCard 3.0 specification and
|
||||
* puts pieces into mInterpreter.
|
||||
*/
|
||||
/*
|
||||
* param-value = ptext / quoted-string
|
||||
* quoted-string = DQUOTE QSAFE-CHAR DQUOTE
|
||||
* QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-ASCII
|
||||
* ; Any character except CTLs, DQUOTE
|
||||
*
|
||||
* QSAFE-CHAR must not contain DQUOTE, including escaped one (\")
|
||||
*/
|
||||
private void splitAndPutParam(VCardProperty property, String paramName, String paramValue) {
|
||||
// "comma,separated:inside.dquote",pref
|
||||
// -->
|
||||
// - comma,separated:inside.dquote
|
||||
// - pref
|
||||
//
|
||||
// Note: Though there's a code, we don't need to take much care of
|
||||
// wrongly-added quotes like the example above, as they induce
|
||||
// parse errors at the top level (when splitting a line into parts).
|
||||
StringBuilder builder = null; // Delay initialization.
|
||||
boolean insideDquote = false;
|
||||
final int length = paramValue.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
final char ch = paramValue.charAt(i);
|
||||
if (ch == '"') {
|
||||
if (insideDquote) {
|
||||
// End of Dquote.
|
||||
property.addParameter(paramName, encodeParamValue(builder.toString()));
|
||||
builder = null;
|
||||
insideDquote = false;
|
||||
} else {
|
||||
if (builder != null) {
|
||||
if (builder.length() > 0) {
|
||||
// e.g.
|
||||
// pref"quoted"
|
||||
Log.w(LOG_TAG, "Unexpected Dquote inside property.");
|
||||
} else {
|
||||
// e.g.
|
||||
// pref,"quoted"
|
||||
// "quoted",pref
|
||||
property.addParameter(paramName, encodeParamValue(builder.toString()));
|
||||
}
|
||||
}
|
||||
insideDquote = true;
|
||||
}
|
||||
} else if (ch == ',' && !insideDquote) {
|
||||
if (builder == null) {
|
||||
Log.w(LOG_TAG, "Comma is used before actual string comes. (" +
|
||||
paramValue + ")");
|
||||
} else {
|
||||
property.addParameter(paramName, encodeParamValue(builder.toString()));
|
||||
builder = null;
|
||||
}
|
||||
} else {
|
||||
// To stop creating empty StringBuffer at the end of parameter,
|
||||
// we delay creating this object until this point.
|
||||
if (builder == null) {
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
if (insideDquote) {
|
||||
// e.g.
|
||||
// "non-quote-at-end
|
||||
Log.d(LOG_TAG, "Dangling Dquote.");
|
||||
}
|
||||
if (builder != null) {
|
||||
if (builder.length() == 0) {
|
||||
Log.w(LOG_TAG, "Unintended behavior. We must not see empty StringBuilder " +
|
||||
"at the end of parameter value parsing.");
|
||||
} else {
|
||||
property.addParameter(paramName, encodeParamValue(builder.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a param value using UTF-8.
|
||||
*/
|
||||
protected String encodeParamValue(String paramValue) {
|
||||
return VCardUtils.convertStringCharset(
|
||||
paramValue, VCardConfig.DEFAULT_INTERMEDIATE_CHARSET, "UTF-8");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleAgent(VCardProperty property) {
|
||||
// The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.1.
|
||||
//
|
||||
// e.g.
|
||||
// AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n
|
||||
// TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n
|
||||
// ET:jfriday@host.com\nEND:VCARD\n
|
||||
//
|
||||
// TODO: fix this.
|
||||
//
|
||||
// issue:
|
||||
// vCard 3.0 also allows this as an example.
|
||||
//
|
||||
// AGENT;VALUE=uri:
|
||||
// CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com
|
||||
//
|
||||
// This is not vCard. Should we support this?
|
||||
//
|
||||
// Just ignore the line for now, since we cannot know how to handle it...
|
||||
if (!mEmittedAgentWarning) {
|
||||
Log.w(LOG_TAG, "AGENT in vCard 3.0 is not supported yet. Ignore it");
|
||||
mEmittedAgentWarning = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is only called from handlePropertyValue(), which has already
|
||||
* read the first line of this property. With v3.0, the getNonEmptyLine()
|
||||
* routine has already concatenated all following continuation lines.
|
||||
* The routine is implemented in the V21 parser to concatenate v2.1 style
|
||||
* data blocks, but is unnecessary here.
|
||||
*/
|
||||
@Override
|
||||
protected String getBase64(final String firstString)
|
||||
throws IOException, VCardException {
|
||||
return firstString;
|
||||
}
|
||||
|
||||
/**
|
||||
* ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N")
|
||||
* ; \\ encodes \, \n or \N encodes newline
|
||||
* ; \; encodes ;, \, encodes ,
|
||||
*
|
||||
* Note: Apple escapes ':' into '\:' while does not escape '\'
|
||||
*/
|
||||
@Override
|
||||
protected String maybeUnescapeText(final String text) {
|
||||
return unescapeText(text);
|
||||
}
|
||||
|
||||
public static String unescapeText(final String text) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
final int length = text.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char ch = text.charAt(i);
|
||||
if (ch == '\\' && i < length - 1) {
|
||||
final char next_ch = text.charAt(++i);
|
||||
if (next_ch == 'n' || next_ch == 'N') {
|
||||
builder.append("\n");
|
||||
} else {
|
||||
builder.append(next_ch);
|
||||
}
|
||||
} else {
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String maybeUnescapeCharacter(final char ch) {
|
||||
return unescapeCharacter(ch);
|
||||
}
|
||||
|
||||
public static String unescapeCharacter(final char ch) {
|
||||
if (ch == 'n' || ch == 'N') {
|
||||
return "\n";
|
||||
} else {
|
||||
return String.valueOf(ch);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> getKnownPropertyNameSet() {
|
||||
return VCardParser_V30.sKnownPropertyNameSet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Basic implementation parsing vCard 4.0.
|
||||
* </p>
|
||||
* <p>
|
||||
* vCard 4.0 is not published yet. Also this implementation is premature.
|
||||
* </p>
|
||||
* @hide
|
||||
*/
|
||||
/* package */ class VCardParserImpl_V40 extends VCardParserImpl_V30 {
|
||||
// private static final String LOG_TAG = VCardConstants.LOG_TAG;
|
||||
|
||||
public VCardParserImpl_V40() {
|
||||
super();
|
||||
}
|
||||
|
||||
public VCardParserImpl_V40(final int vcardType) {
|
||||
super(vcardType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVersion() {
|
||||
return VCardConfig.VERSION_40;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getVersionString() {
|
||||
return VCardConstants.VERSION_V40;
|
||||
}
|
||||
|
||||
/**
|
||||
* We escape "\N" into new line for safety.
|
||||
*/
|
||||
@Override
|
||||
protected String maybeUnescapeText(final String text) {
|
||||
return unescapeText(text);
|
||||
}
|
||||
|
||||
public static String unescapeText(final String text) {
|
||||
// TODO: more strictly, vCard 4.0 requires different type of unescaping rule
|
||||
// toward each property.
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final int length = text.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char ch = text.charAt(i);
|
||||
if (ch == '\\' && i < length - 1) {
|
||||
final char next_ch = text.charAt(++i);
|
||||
if (next_ch == 'n' || next_ch == 'N') {
|
||||
builder.append("\n");
|
||||
} else {
|
||||
builder.append(next_ch);
|
||||
}
|
||||
} else {
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String unescapeCharacter(final char ch) {
|
||||
if (ch == 'n' || ch == 'N') {
|
||||
return "\n";
|
||||
} else {
|
||||
return String.valueOf(ch);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> getKnownPropertyNameSet() {
|
||||
return VCardParser_V40.sKnownPropertyNameSet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import com.android.vcard.exception.VCardException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* </p>
|
||||
* vCard parser for vCard 2.1. See the specification for more detail about the spec itself.
|
||||
* </p>
|
||||
* <p>
|
||||
* The spec is written in 1996, and currently various types of "vCard 2.1" exist.
|
||||
* To handle real the world vCard formats appropriately and effectively, this class does not
|
||||
* obey with strict vCard 2.1.
|
||||
* In stead, not only vCard spec but also real world vCard is considered.
|
||||
* </p>
|
||||
* e.g. A lot of devices and softwares let vCard importer/exporter to use
|
||||
* the PNG format to determine the type of image, while it is not allowed in
|
||||
* the original specification. As of 2010, we can see even the FLV format
|
||||
* (possible in Japanese mobile phones).
|
||||
* </p>
|
||||
*/
|
||||
public final class VCardParser_V21 extends VCardParser {
|
||||
/**
|
||||
* A unmodifiable Set storing the property names available in the vCard 2.1 specification.
|
||||
*/
|
||||
/* package */ static final Set<String> sKnownPropertyNameSet =
|
||||
Collections.unmodifiableSet(new HashSet<String>(
|
||||
Arrays.asList("BEGIN", "END", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
|
||||
"VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
|
||||
"BDAY", "ROLE", "REV", "UID", "KEY", "MAILER")));
|
||||
|
||||
/**
|
||||
* A unmodifiable Set storing the types known in vCard 2.1.
|
||||
*/
|
||||
/* package */ static final Set<String> sKnownTypeSet =
|
||||
Collections.unmodifiableSet(new HashSet<String>(
|
||||
Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK",
|
||||
"PREF", "VOICE", "FAX", "MSG", "CELL", "PAGER", "BBS",
|
||||
"MODEM", "CAR", "ISDN", "VIDEO", "AOL", "APPLELINK",
|
||||
"ATTMAIL", "CIS", "EWORLD", "INTERNET", "IBMMAIL",
|
||||
"MCIMAIL", "POWERSHARE", "PRODIGY", "TLX", "X400", "GIF",
|
||||
"CGM", "WMF", "BMP", "MET", "PMB", "DIB", "PICT", "TIFF",
|
||||
"PDF", "PS", "JPEG", "QTIME", "MPEG", "MPEG2", "AVI",
|
||||
"WAVE", "AIFF", "PCM", "X509", "PGP")));
|
||||
|
||||
/**
|
||||
* A unmodifiable Set storing the values for the type "VALUE", available in the vCard 2.1.
|
||||
*/
|
||||
/* package */ static final Set<String> sKnownValueSet =
|
||||
Collections.unmodifiableSet(new HashSet<String>(
|
||||
Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID")));
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A unmodifiable Set storing the values for the type "ENCODING", available in the vCard 2.1.
|
||||
* </p>
|
||||
* <p>
|
||||
* Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
|
||||
* We allow it for safety.
|
||||
* </p>
|
||||
*/
|
||||
/* package */ static final Set<String> sAvailableEncoding =
|
||||
Collections.unmodifiableSet(new HashSet<String>(
|
||||
Arrays.asList(VCardConstants.PARAM_ENCODING_7BIT,
|
||||
VCardConstants.PARAM_ENCODING_8BIT,
|
||||
VCardConstants.PARAM_ENCODING_QP,
|
||||
VCardConstants.PARAM_ENCODING_BASE64,
|
||||
VCardConstants.PARAM_ENCODING_B)));
|
||||
|
||||
private final VCardParserImpl_V21 mVCardParserImpl;
|
||||
|
||||
public VCardParser_V21() {
|
||||
mVCardParserImpl = new VCardParserImpl_V21();
|
||||
}
|
||||
|
||||
public VCardParser_V21(int vcardType) {
|
||||
mVCardParserImpl = new VCardParserImpl_V21(vcardType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterpreter(VCardInterpreter interpreter) {
|
||||
mVCardParserImpl.addInterpreter(interpreter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parse(InputStream is) throws IOException, VCardException {
|
||||
mVCardParserImpl.parse(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseOne(InputStream is) throws IOException, VCardException {
|
||||
mVCardParserImpl.parseOne(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
mVCardParserImpl.cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import com.android.vcard.exception.VCardException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* vCard parser for vCard 3.0. See RFC 2426 for more detail.
|
||||
* </p>
|
||||
* <p>
|
||||
* This parser allows vCard format which is not allowed in the RFC, since
|
||||
* we have seen several vCard 3.0 files which don't comply with it.
|
||||
* </p>
|
||||
* <p>
|
||||
* e.g. vCard 3.0 does not allow "CHARSET" attribute, but some actual files
|
||||
* have it and they uses non UTF-8 charsets. UTF-8 is recommended in RFC 2426,
|
||||
* but it is not a must. We silently allow "CHARSET".
|
||||
* </p>
|
||||
*/
|
||||
public class VCardParser_V30 extends VCardParser {
|
||||
/* package */ static final Set<String> sKnownPropertyNameSet =
|
||||
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
|
||||
"BEGIN", "END", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
|
||||
"VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
|
||||
"BDAY", "ROLE", "REV", "UID", "KEY", "MAILER", // 2.1
|
||||
"NAME", "PROFILE", "SOURCE", "NICKNAME", "CLASS",
|
||||
"SORT-STRING", "CATEGORIES", "PRODID", // 3.0
|
||||
"IMPP"))); // RFC 4770
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A unmodifiable Set storing the values for the type "ENCODING", available in the vCard 3.0.
|
||||
* </p>
|
||||
* <p>
|
||||
* Though vCard 2.1 specification does not allow "7BIT" or "BASE64", we allow them for safety.
|
||||
* </p>
|
||||
* <p>
|
||||
* "QUOTED-PRINTABLE" is not allowed in vCard 3.0 and not in this parser either,
|
||||
* because the encoding ambiguates how the vCard file to be parsed.
|
||||
* </p>
|
||||
*/
|
||||
/* package */ static final Set<String> sAcceptableEncoding =
|
||||
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
|
||||
VCardConstants.PARAM_ENCODING_7BIT,
|
||||
VCardConstants.PARAM_ENCODING_8BIT,
|
||||
VCardConstants.PARAM_ENCODING_BASE64,
|
||||
VCardConstants.PARAM_ENCODING_B)));
|
||||
|
||||
private final VCardParserImpl_V30 mVCardParserImpl;
|
||||
|
||||
public VCardParser_V30() {
|
||||
mVCardParserImpl = new VCardParserImpl_V30();
|
||||
}
|
||||
|
||||
public VCardParser_V30(int vcardType) {
|
||||
mVCardParserImpl = new VCardParserImpl_V30(vcardType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterpreter(VCardInterpreter interpreter) {
|
||||
mVCardParserImpl.addInterpreter(interpreter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parse(InputStream is) throws IOException, VCardException {
|
||||
mVCardParserImpl.parse(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseOne(InputStream is) throws IOException, VCardException {
|
||||
mVCardParserImpl.parseOne(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
mVCardParserImpl.cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import com.android.vcard.exception.VCardException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* vCard parser for vCard 4.0. DO NOT USE IN PRODUCTION.
|
||||
* </p>
|
||||
* <p>
|
||||
* Currently this parser is based on vCard 4.0 specification rev 15 (partly).
|
||||
* Note that some of current implementation lack basic capability required in vCard 4.0.
|
||||
* (e.g. PHOTO has data parameter in rev 15 while this implementation requires "ENCODING=b")
|
||||
* </p>
|
||||
*/
|
||||
public class VCardParser_V40 extends VCardParser {
|
||||
/* package */ static final Set<String> sKnownPropertyNameSet =
|
||||
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
|
||||
"BEGIN", "END", "VERSION",
|
||||
"SOURCE", "KIND", "FN", "N", "NICKNAME",
|
||||
"PHOTO", "BDAY", "ANNIVERSARY", "GENDER", "ADR", "TEL",
|
||||
"EMAIL", "IMPP", "LANG", "TZ", "GEO", "TITLE", "ROLE",
|
||||
"LOGO", "ORG", "MEMBER", "RELATED", "CATEGORIES",
|
||||
"NOTE", "PRODID", "REV", "SOUND", "UID", "CLIENTPIDMAP",
|
||||
"URL", "KEY", "FBURL", "CALENDRURI", "CALURI", "XML")));
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A unmodifiable Set storing the values for the type "ENCODING", available in vCard 4.0.
|
||||
* </p>
|
||||
*/
|
||||
/* package */ static final Set<String> sAcceptableEncoding =
|
||||
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
|
||||
VCardConstants.PARAM_ENCODING_8BIT,
|
||||
VCardConstants.PARAM_ENCODING_B)));
|
||||
|
||||
private final VCardParserImpl_V40 mVCardParserImpl;
|
||||
|
||||
public VCardParser_V40() {
|
||||
mVCardParserImpl = new VCardParserImpl_V40();
|
||||
}
|
||||
|
||||
public VCardParser_V40(int vcardType) {
|
||||
mVCardParserImpl = new VCardParserImpl_V40(vcardType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterpreter(VCardInterpreter interpreter) {
|
||||
mVCardParserImpl.addInterpreter(interpreter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parse(InputStream is) throws IOException, VCardException {
|
||||
mVCardParserImpl.parse(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseOne(InputStream is) throws IOException, VCardException {
|
||||
mVCardParserImpl.parseOne(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
mVCardParserImpl.cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
/**
|
||||
* Callback functionality which can be used with
|
||||
* {@link VCardComposer#setPhoneNumberTranslationCallback(VCardPhoneNumberTranslationCallback)}.
|
||||
* See the doc for the method.
|
||||
*
|
||||
* <p>
|
||||
* TODO: this should be more generic
|
||||
* </p>
|
||||
*
|
||||
* @hide This will change
|
||||
*/
|
||||
public interface VCardPhoneNumberTranslationCallback {
|
||||
/**
|
||||
* Called when a phone number is being handled.
|
||||
* @return formatted phone number.
|
||||
*/
|
||||
public String onValueReceived(String rawValue, int type, String label, boolean isPrimary);
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents vCard's property, or logical "one line" of each vCard entry.
|
||||
*
|
||||
* e.g.
|
||||
* Given a vCard below, objects for <code>N:name</code>, <code>TEL:1111111111</code> are
|
||||
* "property".
|
||||
*
|
||||
* <code>
|
||||
* BEGIN:VCARD
|
||||
* N:name
|
||||
* TEL:1111111111
|
||||
* END:VCARD
|
||||
* </code>
|
||||
*
|
||||
* vCard's property has three elements: name, parameter (or param), and value. Name is the name
|
||||
* of each property. Parameter or param is additional information for the property. Value is one
|
||||
* or multiple values representing the parameter.
|
||||
*
|
||||
* e.g.
|
||||
* <code>N;CHARSET=UTF-8:Joe;Due;M.;Mr.;Ph.D.</code>, has "N" for name, "CHALSET=UTF-8" for param,
|
||||
* and "Joe;Due;M.;Mr.;Ph.D." for value.
|
||||
*
|
||||
* Usually params are represented as "key=value" pair, but not always
|
||||
* (The property <code>TEL;WORK;VOICE:(111) 555-1212</code> has two params without key "TYPE",
|
||||
* which are same as "TYPE=WORK" and "TYPE=VOICE". In vCard 3.0, we can even express them as
|
||||
* "TYPE=WORK,VOICE").
|
||||
*
|
||||
* Sometimes (not always) value can be separated by semi-colon. In the example above "Joe;Due;;;"
|
||||
* should be interpreted as five strings: "Joe" (for family name), "Due" (for given name), "M."
|
||||
* (for middle name), "Mr." (for prefix), and "Ph.D." (for suffix). Whether the value is
|
||||
* separable or not is specified by vCard specs.
|
||||
*/
|
||||
public class VCardProperty {
|
||||
private static final String LOG_TAG = VCardConstants.LOG_TAG;
|
||||
private String mName;
|
||||
private List<String> mGroupList;
|
||||
|
||||
private Map<String, Collection<String>> mParameterMap =
|
||||
new HashMap<String, Collection<String>>();
|
||||
private String mRawValue;
|
||||
|
||||
private List<String> mValueList;
|
||||
private byte[] mByteValue;
|
||||
|
||||
public void setName(String name) {
|
||||
if (mName != null) {
|
||||
Log.w(LOG_TAG, String.format("Property name is re-defined " +
|
||||
"(existing: %s, requested: %s", mName, name));
|
||||
}
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public void addGroup(String group) {
|
||||
if (mGroupList == null) {
|
||||
mGroupList = new ArrayList<String>();
|
||||
}
|
||||
mGroupList.add(group);
|
||||
}
|
||||
|
||||
public void setParameter(final String paramName, final String paramValue) {
|
||||
mParameterMap.clear();
|
||||
addParameter(paramName, paramValue);
|
||||
}
|
||||
|
||||
public void addParameter(final String paramName, final String paramValue) {
|
||||
Collection<String> values;
|
||||
if (!mParameterMap.containsKey(paramName)) {
|
||||
if (paramName.equals("TYPE")) {
|
||||
values = new HashSet<String>();
|
||||
} else {
|
||||
values = new ArrayList<String>();
|
||||
}
|
||||
mParameterMap.put(paramName, values);
|
||||
} else {
|
||||
values = mParameterMap.get(paramName);
|
||||
}
|
||||
values.add(paramValue);
|
||||
}
|
||||
|
||||
public void setRawValue(String rawValue) {
|
||||
mRawValue = rawValue;
|
||||
}
|
||||
|
||||
// TODO: would be much better to have translateRawValue() functionality instead of forcing
|
||||
// VCardParserImpl does this job.
|
||||
|
||||
public void setValues(String... propertyValues) {
|
||||
mValueList = Arrays.asList(propertyValues);
|
||||
}
|
||||
|
||||
public void setValues(List<String> propertyValueList) {
|
||||
mValueList = propertyValueList;
|
||||
}
|
||||
|
||||
public void addValues(String... propertyValues) {
|
||||
if (mValueList == null) {
|
||||
mValueList = Arrays.asList(propertyValues);
|
||||
} else {
|
||||
mValueList.addAll(Arrays.asList(propertyValues));
|
||||
}
|
||||
}
|
||||
|
||||
public void addValues(List<String> propertyValueList) {
|
||||
if (mValueList == null) {
|
||||
mValueList = new ArrayList<String>(propertyValueList);
|
||||
} else {
|
||||
mValueList.addAll(propertyValueList);
|
||||
}
|
||||
}
|
||||
|
||||
public void setByteValue(byte[] byteValue) {
|
||||
mByteValue = byteValue;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public List<String> getGroupList() {
|
||||
return mGroupList;
|
||||
}
|
||||
|
||||
public Map<String, Collection<String>> getParameterMap() {
|
||||
return mParameterMap;
|
||||
}
|
||||
|
||||
public Collection<String> getParameters(String type) {
|
||||
return mParameterMap.get(type);
|
||||
}
|
||||
|
||||
public String getRawValue() {
|
||||
return mRawValue;
|
||||
}
|
||||
|
||||
public List<String> getValueList() {
|
||||
return mValueList;
|
||||
}
|
||||
|
||||
public byte[] getByteValue() {
|
||||
return mByteValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The class which tries to detects the source of a vCard file from its contents.
|
||||
* </p>
|
||||
* <p>
|
||||
* The specification of vCard (including both 2.1 and 3.0) is not so strict as to
|
||||
* guess its format just by reading beginning few lines (usually we can, but in
|
||||
* some most pessimistic case, we cannot until at almost the end of the file).
|
||||
* Also we cannot store all vCard entries in memory, while there's no specification
|
||||
* how big the vCard entry would become after the parse.
|
||||
* </p>
|
||||
* <p>
|
||||
* This class is usually used for the "first scan", in which we can understand which vCard
|
||||
* version is used (and how many entries exist in a file).
|
||||
* </p>
|
||||
*/
|
||||
public class VCardSourceDetector implements VCardInterpreter {
|
||||
private static final String LOG_TAG = VCardConstants.LOG_TAG;
|
||||
|
||||
private static Set<String> APPLE_SIGNS = new HashSet<String>(Arrays.asList(
|
||||
"X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", "X-PHONETIC-LAST-NAME",
|
||||
"X-ABADR", "X-ABUID"));
|
||||
|
||||
private static Set<String> JAPANESE_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
|
||||
"X-GNO", "X-GN", "X-REDUCTION"));
|
||||
|
||||
private static Set<String> WINDOWS_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
|
||||
"X-MICROSOFT-ASST_TEL", "X-MICROSOFT-ASSISTANT", "X-MICROSOFT-OFFICELOC"));
|
||||
|
||||
// Note: these signes appears before the signs of the other type (e.g. "X-GN").
|
||||
// In other words, Japanese FOMA mobile phones are detected as FOMA, not JAPANESE_MOBILE_PHONES.
|
||||
private static Set<String> FOMA_SIGNS = new HashSet<String>(Arrays.asList(
|
||||
"X-SD-VERN", "X-SD-FORMAT_VER", "X-SD-CATEGORIES", "X-SD-CLASS", "X-SD-DCREATED",
|
||||
"X-SD-DESCRIPTION"));
|
||||
private static String TYPE_FOMA_CHARSET_SIGN = "X-SD-CHAR_CODE";
|
||||
|
||||
/**
|
||||
* Represents that no estimation is available. Users of this class is able to this
|
||||
* constant when you don't want to let a vCard parser rely on estimation for parse type.
|
||||
*/
|
||||
public static final int PARSE_TYPE_UNKNOWN = 0;
|
||||
|
||||
// For Apple's software, which does not mean this type is effective for all its products.
|
||||
// We confirmed they usually use UTF-8, but not sure about vCard type.
|
||||
private static final int PARSE_TYPE_APPLE = 1;
|
||||
// For Japanese mobile phones, which are usually using Shift_JIS as a charset.
|
||||
private static final int PARSE_TYPE_MOBILE_PHONE_JP = 2;
|
||||
// For some of mobile phones released from DoCoMo.
|
||||
private static final int PARSE_TYPE_DOCOMO_FOMA = 3;
|
||||
// For Japanese Windows Mobile phones. It's version is supposed to be 6.5.
|
||||
private static final int PARSE_TYPE_WINDOWS_MOBILE_V65_JP = 4;
|
||||
|
||||
private int mParseType = PARSE_TYPE_UNKNOWN;
|
||||
|
||||
private int mVersion = -1; // -1 == unknown
|
||||
|
||||
// Some mobile phones (like FOMA) tells us the charset of the data.
|
||||
private String mSpecifiedCharset;
|
||||
|
||||
@Override
|
||||
public void onVCardStarted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVCardEnded() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryStarted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryEnded() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyCreated(VCardProperty property) {
|
||||
final String propertyName = property.getName();
|
||||
final List<String> valueList = property.getValueList();
|
||||
|
||||
if (propertyName.equalsIgnoreCase(VCardConstants.PROPERTY_VERSION)
|
||||
&& valueList.size() > 0) {
|
||||
final String versionString = valueList.get(0);
|
||||
if (versionString.equals(VCardConstants.VERSION_V21)) {
|
||||
mVersion = VCardConfig.VERSION_21;
|
||||
} else if (versionString.equals(VCardConstants.VERSION_V30)) {
|
||||
mVersion = VCardConfig.VERSION_30;
|
||||
} else if (versionString.equals(VCardConstants.VERSION_V40)) {
|
||||
mVersion = VCardConfig.VERSION_40;
|
||||
} else {
|
||||
Log.w(LOG_TAG, "Invalid version string: " + versionString);
|
||||
}
|
||||
} else if (propertyName.equalsIgnoreCase(TYPE_FOMA_CHARSET_SIGN)) {
|
||||
mParseType = PARSE_TYPE_DOCOMO_FOMA;
|
||||
if (valueList.size() > 0) {
|
||||
mSpecifiedCharset = valueList.get(0);
|
||||
}
|
||||
}
|
||||
if (mParseType != PARSE_TYPE_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
if (WINDOWS_MOBILE_PHONE_SIGNS.contains(propertyName)) {
|
||||
mParseType = PARSE_TYPE_WINDOWS_MOBILE_V65_JP;
|
||||
} else if (FOMA_SIGNS.contains(propertyName)) {
|
||||
mParseType = PARSE_TYPE_DOCOMO_FOMA;
|
||||
} else if (JAPANESE_MOBILE_PHONE_SIGNS.contains(propertyName)) {
|
||||
mParseType = PARSE_TYPE_MOBILE_PHONE_JP;
|
||||
} else if (APPLE_SIGNS.contains(propertyName)) {
|
||||
mParseType = PARSE_TYPE_APPLE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The available type can be used with vCard parser. You probably need to
|
||||
* use {{@link #getEstimatedCharset()} to understand the charset to be used.
|
||||
*/
|
||||
public int getEstimatedType() {
|
||||
switch (mParseType) {
|
||||
case PARSE_TYPE_DOCOMO_FOMA:
|
||||
return VCardConfig.VCARD_TYPE_DOCOMO;
|
||||
case PARSE_TYPE_MOBILE_PHONE_JP:
|
||||
return VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE;
|
||||
case PARSE_TYPE_APPLE:
|
||||
case PARSE_TYPE_WINDOWS_MOBILE_V65_JP:
|
||||
default: {
|
||||
if (mVersion == VCardConfig.VERSION_21) {
|
||||
return VCardConfig.VCARD_TYPE_V21_GENERIC;
|
||||
} else if (mVersion == VCardConfig.VERSION_30) {
|
||||
return VCardConfig.VCARD_TYPE_V30_GENERIC;
|
||||
} else if (mVersion == VCardConfig.VERSION_40) {
|
||||
return VCardConfig.VCARD_TYPE_V40_GENERIC;
|
||||
} else {
|
||||
return VCardConfig.VCARD_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns charset String guessed from the source's properties.
|
||||
* This method must be called after parsing target file(s).
|
||||
* </p>
|
||||
* @return Charset String. Null is returned if guessing the source fails.
|
||||
*/
|
||||
public String getEstimatedCharset() {
|
||||
if (TextUtils.isEmpty(mSpecifiedCharset)) {
|
||||
return mSpecifiedCharset;
|
||||
}
|
||||
switch (mParseType) {
|
||||
case PARSE_TYPE_WINDOWS_MOBILE_V65_JP:
|
||||
case PARSE_TYPE_DOCOMO_FOMA:
|
||||
case PARSE_TYPE_MOBILE_PHONE_JP:
|
||||
return "SHIFT_JIS";
|
||||
case PARSE_TYPE_APPLE:
|
||||
return "UTF-8";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,855 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard;
|
||||
|
||||
import android.provider.ContactsContract.CommonDataKinds.Im;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.vcard.exception.VCardException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utilities for VCard handling codes.
|
||||
*/
|
||||
public class VCardUtils {
|
||||
private static final String LOG_TAG = VCardConstants.LOG_TAG;
|
||||
|
||||
/**
|
||||
* See org.apache.commons.codec.DecoderException
|
||||
*/
|
||||
private static class DecoderException extends Exception {
|
||||
public DecoderException(String pMessage) {
|
||||
super(pMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See org.apache.commons.codec.net.QuotedPrintableCodec
|
||||
*/
|
||||
private static class QuotedPrintableCodecPort {
|
||||
private static byte ESCAPE_CHAR = '=';
|
||||
public static final byte[] decodeQuotedPrintable(byte[] bytes)
|
||||
throws DecoderException {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
int b = bytes[i];
|
||||
if (b == ESCAPE_CHAR) {
|
||||
try {
|
||||
int u = Character.digit((char) bytes[++i], 16);
|
||||
int l = Character.digit((char) bytes[++i], 16);
|
||||
if (u == -1 || l == -1) {
|
||||
throw new DecoderException("Invalid quoted-printable encoding");
|
||||
}
|
||||
buffer.write((char) ((u << 4) + l));
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new DecoderException("Invalid quoted-printable encoding");
|
||||
}
|
||||
} else {
|
||||
buffer.write(b);
|
||||
}
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ported methods which are hidden in {@link PhoneNumberUtils}.
|
||||
*/
|
||||
public static class PhoneNumberUtilsPort {
|
||||
public static String formatNumber(String source, int defaultFormattingType) {
|
||||
final SpannableStringBuilder text = new SpannableStringBuilder(source);
|
||||
PhoneNumberUtils.formatNumber(text, defaultFormattingType);
|
||||
return text.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ported methods which are hidden in {@link TextUtils}.
|
||||
*/
|
||||
public static class TextUtilsPort {
|
||||
public static boolean isPrintableAscii(final char c) {
|
||||
final int asciiFirst = 0x20;
|
||||
final int asciiLast = 0x7E; // included
|
||||
return (asciiFirst <= c && c <= asciiLast) || c == '\r' || c == '\n';
|
||||
}
|
||||
|
||||
public static boolean isPrintableAsciiOnly(final CharSequence str) {
|
||||
final int len = str.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!isPrintableAscii(str.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is
|
||||
// converted to two parameter Strings. These only contain some minor fields valid in both
|
||||
// vCard and current (as of 2009-08-07) Contacts structure.
|
||||
private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS;
|
||||
private static final Set<String> sPhoneTypesUnknownToContactsSet;
|
||||
private static final Map<String, Integer> sKnownPhoneTypeMap_StoI;
|
||||
private static final Map<Integer, String> sKnownImPropNameMap_ItoS;
|
||||
private static final Set<String> sMobilePhoneLabelSet;
|
||||
|
||||
static {
|
||||
sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
|
||||
sKnownPhoneTypeMap_StoI = new HashMap<String, Integer>();
|
||||
|
||||
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, VCardConstants.PARAM_TYPE_CAR);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CAR, Phone.TYPE_CAR);
|
||||
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, VCardConstants.PARAM_TYPE_PAGER);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_PAGER, Phone.TYPE_PAGER);
|
||||
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, VCardConstants.PARAM_TYPE_ISDN);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_ISDN, Phone.TYPE_ISDN);
|
||||
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_HOME, Phone.TYPE_HOME);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_WORK, Phone.TYPE_WORK);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CELL, Phone.TYPE_MOBILE);
|
||||
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_OTHER, Phone.TYPE_OTHER);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_CALLBACK,
|
||||
Phone.TYPE_CALLBACK);
|
||||
sKnownPhoneTypeMap_StoI.put(
|
||||
VCardConstants.PARAM_PHONE_EXTRA_TYPE_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_RADIO, Phone.TYPE_RADIO);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_TTY_TDD,
|
||||
Phone.TYPE_TTY_TDD);
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_ASSISTANT,
|
||||
Phone.TYPE_ASSISTANT);
|
||||
// OTHER (default in Android) should correspond to VOICE (default in vCard).
|
||||
sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_VOICE, Phone.TYPE_OTHER);
|
||||
|
||||
sPhoneTypesUnknownToContactsSet = new HashSet<String>();
|
||||
sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MODEM);
|
||||
sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MSG);
|
||||
sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_BBS);
|
||||
sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_VIDEO);
|
||||
|
||||
sKnownImPropNameMap_ItoS = new HashMap<Integer, String>();
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_GOOGLE_TALK,
|
||||
VCardConstants.PROPERTY_X_GOOGLE_TALK);
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_QQ, VCardConstants.PROPERTY_X_QQ);
|
||||
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_NETMEETING, VCardConstants.PROPERTY_X_NETMEETING);
|
||||
|
||||
// \u643A\u5E2F\u96FB\u8A71 = Full-width Hiragana "Keitai-Denwa" (mobile phone)
|
||||
// \u643A\u5E2F = Full-width Hiragana "Keitai" (mobile phone)
|
||||
// \u30B1\u30A4\u30BF\u30A4 = Full-width Katakana "Keitai" (mobile phone)
|
||||
// \uFF79\uFF72\uFF80\uFF72 = Half-width Katakana "Keitai" (mobile phone)
|
||||
sMobilePhoneLabelSet = new HashSet<String>(Arrays.asList(
|
||||
"MOBILE", "\u643A\u5E2F\u96FB\u8A71", "\u643A\u5E2F", "\u30B1\u30A4\u30BF\u30A4",
|
||||
"\uFF79\uFF72\uFF80\uFF72"));
|
||||
}
|
||||
|
||||
public static String getPhoneTypeString(Integer type) {
|
||||
return sKnownPhoneTypesMap_ItoS.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Interger when the given types can be parsed as known type. Returns String object
|
||||
* when not, which should be set to label.
|
||||
*/
|
||||
public static Object getPhoneTypeFromStrings(Collection<String> types,
|
||||
String number) {
|
||||
if (number == null) {
|
||||
number = "";
|
||||
}
|
||||
int type = -1;
|
||||
String label = null;
|
||||
boolean isFax = false;
|
||||
boolean hasPref = false;
|
||||
|
||||
if (types != null) {
|
||||
for (final String typeStringOrg : types) {
|
||||
if (typeStringOrg == null) {
|
||||
continue;
|
||||
}
|
||||
final String typeStringUpperCase = typeStringOrg.toUpperCase();
|
||||
if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_PREF)) {
|
||||
hasPref = true;
|
||||
} else if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_FAX)) {
|
||||
isFax = true;
|
||||
} else {
|
||||
final String labelCandidate;
|
||||
if (typeStringUpperCase.startsWith("X-") && type < 0) {
|
||||
labelCandidate = typeStringOrg.substring(2);
|
||||
} else {
|
||||
labelCandidate = typeStringOrg;
|
||||
}
|
||||
if (labelCandidate.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
// e.g. "home" -> TYPE_HOME
|
||||
final Integer tmp = sKnownPhoneTypeMap_StoI.get(labelCandidate.toUpperCase());
|
||||
if (tmp != null) {
|
||||
final int typeCandidate = tmp;
|
||||
// 1. If a type isn't specified yet, we'll choose the new type candidate.
|
||||
// 2. If the current type is default one (OTHER) or custom one, we'll
|
||||
// prefer more specific types specified in the vCard. Note that OTHER and
|
||||
// the other different types may appear simultaneously here, since vCard
|
||||
// allow to have VOICE and HOME/WORK in one line.
|
||||
// e.g. "TEL;WORK;VOICE:1" -> WORK + OTHER -> Type should be WORK
|
||||
// 3. TYPE_PAGER is prefered when the number contains @ surronded by
|
||||
// a pager number and a domain name.
|
||||
// e.g.
|
||||
// o 1111@domain.com
|
||||
// x @domain.com
|
||||
// x 1111@
|
||||
final int indexOfAt = number.indexOf("@");
|
||||
if ((typeCandidate == Phone.TYPE_PAGER
|
||||
&& 0 < indexOfAt && indexOfAt < number.length() - 1)
|
||||
|| type < 0
|
||||
|| type == Phone.TYPE_CUSTOM
|
||||
|| type == Phone.TYPE_OTHER) {
|
||||
type = tmp;
|
||||
}
|
||||
} else if (type < 0) {
|
||||
type = Phone.TYPE_CUSTOM;
|
||||
label = labelCandidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type < 0) {
|
||||
if (hasPref) {
|
||||
type = Phone.TYPE_MAIN;
|
||||
} else {
|
||||
// default to TYPE_OTHER
|
||||
type = Phone.TYPE_OTHER;
|
||||
}
|
||||
}
|
||||
if (isFax) {
|
||||
if (type == Phone.TYPE_HOME) {
|
||||
type = Phone.TYPE_FAX_HOME;
|
||||
} else if (type == Phone.TYPE_WORK) {
|
||||
type = Phone.TYPE_FAX_WORK;
|
||||
} else if (type == Phone.TYPE_OTHER) {
|
||||
type = Phone.TYPE_OTHER_FAX;
|
||||
}
|
||||
}
|
||||
if (type == Phone.TYPE_CUSTOM) {
|
||||
return label;
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean isMobilePhoneLabel(final String label) {
|
||||
// For backward compatibility.
|
||||
// Detail: Until Donut, there isn't TYPE_MOBILE for email while there is now.
|
||||
// To support mobile type at that time, this custom label had been used.
|
||||
return ("_AUTO_CELL".equals(label) || sMobilePhoneLabelSet.contains(label));
|
||||
}
|
||||
|
||||
public static boolean isValidInV21ButUnknownToContactsPhoteType(final String label) {
|
||||
return sPhoneTypesUnknownToContactsSet.contains(label);
|
||||
}
|
||||
|
||||
public static String getPropertyNameForIm(final int protocol) {
|
||||
return sKnownImPropNameMap_ItoS.get(protocol);
|
||||
}
|
||||
|
||||
public static String[] sortNameElements(final int nameOrder,
|
||||
final String familyName, final String middleName, final String givenName) {
|
||||
final String[] list = new String[3];
|
||||
final int nameOrderType = VCardConfig.getNameOrderType(nameOrder);
|
||||
switch (nameOrderType) {
|
||||
case VCardConfig.NAME_ORDER_JAPANESE: {
|
||||
if (containsOnlyPrintableAscii(familyName) &&
|
||||
containsOnlyPrintableAscii(givenName)) {
|
||||
list[0] = givenName;
|
||||
list[1] = middleName;
|
||||
list[2] = familyName;
|
||||
} else {
|
||||
list[0] = familyName;
|
||||
list[1] = middleName;
|
||||
list[2] = givenName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VCardConfig.NAME_ORDER_EUROPE: {
|
||||
list[0] = middleName;
|
||||
list[1] = givenName;
|
||||
list[2] = familyName;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
list[0] = givenName;
|
||||
list[1] = middleName;
|
||||
list[2] = familyName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static int getPhoneNumberFormat(final int vcardType) {
|
||||
if (VCardConfig.isJapaneseDevice(vcardType)) {
|
||||
return PhoneNumberUtils.FORMAT_JAPAN;
|
||||
} else {
|
||||
return PhoneNumberUtils.FORMAT_NANP;
|
||||
}
|
||||
}
|
||||
|
||||
public static String constructNameFromElements(final int nameOrder,
|
||||
final String familyName, final String middleName, final String givenName) {
|
||||
return constructNameFromElements(nameOrder, familyName, middleName, givenName,
|
||||
null, null);
|
||||
}
|
||||
|
||||
public static String constructNameFromElements(final int nameOrder,
|
||||
final String familyName, final String middleName, final String givenName,
|
||||
final String prefix, final String suffix) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final String[] nameList = sortNameElements(nameOrder, familyName, middleName, givenName);
|
||||
boolean first = true;
|
||||
if (!TextUtils.isEmpty(prefix)) {
|
||||
first = false;
|
||||
builder.append(prefix);
|
||||
}
|
||||
for (final String namePart : nameList) {
|
||||
if (!TextUtils.isEmpty(namePart)) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
builder.append(' ');
|
||||
}
|
||||
builder.append(namePart);
|
||||
}
|
||||
}
|
||||
if (!TextUtils.isEmpty(suffix)) {
|
||||
if (!first) {
|
||||
builder.append(' ');
|
||||
}
|
||||
builder.append(suffix);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the given value into pieces using the delimiter ';' inside it.
|
||||
*
|
||||
* Escaped characters in those values are automatically unescaped into original form.
|
||||
*/
|
||||
public static List<String> constructListFromValue(final String value,
|
||||
final int vcardType) {
|
||||
final List<String> list = new ArrayList<String>();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
final int length = value.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char ch = value.charAt(i);
|
||||
if (ch == '\\' && i < length - 1) {
|
||||
char nextCh = value.charAt(i + 1);
|
||||
final String unescapedString;
|
||||
if (VCardConfig.isVersion40(vcardType)) {
|
||||
unescapedString = VCardParserImpl_V40.unescapeCharacter(nextCh);
|
||||
} else if (VCardConfig.isVersion30(vcardType)) {
|
||||
unescapedString = VCardParserImpl_V30.unescapeCharacter(nextCh);
|
||||
} else {
|
||||
if (!VCardConfig.isVersion21(vcardType)) {
|
||||
// Unknown vCard type
|
||||
Log.w(LOG_TAG, "Unknown vCard type");
|
||||
}
|
||||
unescapedString = VCardParserImpl_V21.unescapeCharacter(nextCh);
|
||||
}
|
||||
|
||||
if (unescapedString != null) {
|
||||
builder.append(unescapedString);
|
||||
i++;
|
||||
} else {
|
||||
builder.append(ch);
|
||||
}
|
||||
} else if (ch == ';') {
|
||||
list.add(builder.toString());
|
||||
builder = new StringBuilder();
|
||||
} else {
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
list.add(builder.toString());
|
||||
return list;
|
||||
}
|
||||
|
||||
public static boolean containsOnlyPrintableAscii(final String...values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
return containsOnlyPrintableAscii(Arrays.asList(values));
|
||||
}
|
||||
|
||||
public static boolean containsOnlyPrintableAscii(final Collection<String> values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
for (final String value : values) {
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
continue;
|
||||
}
|
||||
if (!TextUtilsPort.isPrintableAsciiOnly(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is useful when checking the string should be encoded into quoted-printable
|
||||
* or not, which is required by vCard 2.1.
|
||||
* </p>
|
||||
* <p>
|
||||
* See the definition of "7bit" in vCard 2.1 spec for more information.
|
||||
* </p>
|
||||
*/
|
||||
public static boolean containsOnlyNonCrLfPrintableAscii(final String...values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
return containsOnlyNonCrLfPrintableAscii(Arrays.asList(values));
|
||||
}
|
||||
|
||||
public static boolean containsOnlyNonCrLfPrintableAscii(final Collection<String> values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
final int asciiFirst = 0x20;
|
||||
final int asciiLast = 0x7E; // included
|
||||
for (final String value : values) {
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
continue;
|
||||
}
|
||||
final int length = value.length();
|
||||
for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
|
||||
final int c = value.codePointAt(i);
|
||||
if (!(asciiFirst <= c && c <= asciiLast)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final Set<Character> sUnAcceptableAsciiInV21WordSet =
|
||||
new HashSet<Character>(Arrays.asList('[', ']', '=', ':', '.', ',', ' '));
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is useful since vCard 3.0 often requires the ("X-") properties and groups
|
||||
* should contain only alphabets, digits, and hyphen.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: It is already known some devices (wrongly) outputs properties with characters
|
||||
* which should not be in the field. One example is "X-GOOGLE TALK". We accept
|
||||
* such kind of input but must never output it unless the target is very specific
|
||||
* to the device which is able to parse the malformed input.
|
||||
* </p>
|
||||
*/
|
||||
public static boolean containsOnlyAlphaDigitHyphen(final String...values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
return containsOnlyAlphaDigitHyphen(Arrays.asList(values));
|
||||
}
|
||||
|
||||
public static boolean containsOnlyAlphaDigitHyphen(final Collection<String> values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
final int upperAlphabetFirst = 0x41; // A
|
||||
final int upperAlphabetAfterLast = 0x5b; // [
|
||||
final int lowerAlphabetFirst = 0x61; // a
|
||||
final int lowerAlphabetAfterLast = 0x7b; // {
|
||||
final int digitFirst = 0x30; // 0
|
||||
final int digitAfterLast = 0x3A; // :
|
||||
final int hyphen = '-';
|
||||
for (final String str : values) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
continue;
|
||||
}
|
||||
final int length = str.length();
|
||||
for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
|
||||
int codepoint = str.codePointAt(i);
|
||||
if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetAfterLast) ||
|
||||
(upperAlphabetFirst <= codepoint && codepoint < upperAlphabetAfterLast) ||
|
||||
(digitFirst <= codepoint && codepoint < digitAfterLast) ||
|
||||
(codepoint == hyphen))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean containsOnlyWhiteSpaces(final String...values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
return containsOnlyWhiteSpaces(Arrays.asList(values));
|
||||
}
|
||||
|
||||
public static boolean containsOnlyWhiteSpaces(final Collection<String> values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
for (final String str : values) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
continue;
|
||||
}
|
||||
final int length = str.length();
|
||||
for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
|
||||
if (!Character.isWhitespace(str.codePointAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns true when the given String is categorized as "word" specified in vCard spec 2.1.
|
||||
* </p>
|
||||
* <p>
|
||||
* vCard 2.1 specifies:<br />
|
||||
* word = <any printable 7bit us-ascii except []=:., >
|
||||
* </p>
|
||||
*/
|
||||
public static boolean isV21Word(final String value) {
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
return true;
|
||||
}
|
||||
final int asciiFirst = 0x20;
|
||||
final int asciiLast = 0x7E; // included
|
||||
final int length = value.length();
|
||||
for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
|
||||
final int c = value.codePointAt(i);
|
||||
if (!(asciiFirst <= c && c <= asciiLast) ||
|
||||
sUnAcceptableAsciiInV21WordSet.contains((char)c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final int[] sEscapeIndicatorsV30 = new int[]{
|
||||
':', ';', ',', ' '
|
||||
};
|
||||
|
||||
private static final int[] sEscapeIndicatorsV40 = new int[]{
|
||||
';', ':'
|
||||
};
|
||||
|
||||
/**
|
||||
* <P>
|
||||
* Returns String available as parameter value in vCard 3.0.
|
||||
* </P>
|
||||
* <P>
|
||||
* RFC 2426 requires vCard composer to quote parameter values when it contains
|
||||
* semi-colon, for example (See RFC 2426 for more information).
|
||||
* This method checks whether the given String can be used without quotes.
|
||||
* </P>
|
||||
* <P>
|
||||
* Note: We remove DQUOTE inside the given value silently for now.
|
||||
* </P>
|
||||
*/
|
||||
public static String toStringAsV30ParamValue(String value) {
|
||||
return toStringAsParamValue(value, sEscapeIndicatorsV30);
|
||||
}
|
||||
|
||||
public static String toStringAsV40ParamValue(String value) {
|
||||
return toStringAsParamValue(value, sEscapeIndicatorsV40);
|
||||
}
|
||||
|
||||
private static String toStringAsParamValue(String value, final int[] escapeIndicators) {
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
value = "";
|
||||
}
|
||||
final int asciiFirst = 0x20;
|
||||
final int asciiLast = 0x7E; // included
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final int length = value.length();
|
||||
boolean needQuote = false;
|
||||
for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
|
||||
final int codePoint = value.codePointAt(i);
|
||||
if (codePoint < asciiFirst || codePoint == '"') {
|
||||
// CTL characters and DQUOTE are never accepted. Remove them.
|
||||
continue;
|
||||
}
|
||||
builder.appendCodePoint(codePoint);
|
||||
for (int indicator : escapeIndicators) {
|
||||
if (codePoint == indicator) {
|
||||
needQuote = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String result = builder.toString();
|
||||
return ((result.isEmpty() || VCardUtils.containsOnlyWhiteSpaces(result))
|
||||
? ""
|
||||
: (needQuote ? ('"' + result + '"')
|
||||
: result));
|
||||
}
|
||||
|
||||
public static String toHalfWidthString(final String orgString) {
|
||||
if (TextUtils.isEmpty(orgString)) {
|
||||
return null;
|
||||
}
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final int length = orgString.length();
|
||||
for (int i = 0; i < length; i = orgString.offsetByCodePoints(i, 1)) {
|
||||
// All Japanese character is able to be expressed by char.
|
||||
// Do not need to use String#codepPointAt().
|
||||
final char ch = orgString.charAt(i);
|
||||
final String halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch);
|
||||
if (halfWidthText != null) {
|
||||
builder.append(halfWidthText);
|
||||
} else {
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses the format of input image. Currently just the first few bytes are used.
|
||||
* The type "GIF", "PNG", or "JPEG" is returned when possible. Returns null when
|
||||
* the guess failed.
|
||||
* @param input Image as byte array.
|
||||
* @return The image type or null when the type cannot be determined.
|
||||
*/
|
||||
public static String guessImageType(final byte[] input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
if (input.length >= 3 && input[0] == 'G' && input[1] == 'I' && input[2] == 'F') {
|
||||
return "GIF";
|
||||
} else if (input.length >= 4 && input[0] == (byte) 0x89
|
||||
&& input[1] == 'P' && input[2] == 'N' && input[3] == 'G') {
|
||||
// Note: vCard 2.1 officially does not support PNG, but we may have it and
|
||||
// using X- word like "X-PNG" may not let importers know it is PNG.
|
||||
// So we use the String "PNG" as is...
|
||||
return "PNG";
|
||||
} else if (input.length >= 2 && input[0] == (byte) 0xff
|
||||
&& input[1] == (byte) 0xd8) {
|
||||
return "JPEG";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True when all the given values are null or empty Strings.
|
||||
*/
|
||||
public static boolean areAllEmpty(final String...values) {
|
||||
if (values == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (final String value : values) {
|
||||
if (!TextUtils.isEmpty(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a string looks like it could be an android generated quoted printable.
|
||||
*
|
||||
* Identification of quoted printable is not 100% reliable since it's just ascii. But given
|
||||
* the high number and exact location of generated = signs, there is a high likely-hood that
|
||||
* it would be.
|
||||
*
|
||||
* @return True if it appears like android quoted printable. False otherwise.
|
||||
*/
|
||||
public static boolean appearsLikeAndroidVCardQuotedPrintable(String value) {
|
||||
|
||||
// Quoted printable is always in multiple of 3s. With optional 1 '=' at end.
|
||||
final int remainder = (value.length() % 3);
|
||||
if (value.length() < 2 || (remainder != 1 && remainder != 0)) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < value.length(); i += 3) {
|
||||
if (value.charAt(i) != '=') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//// The methods bellow may be used by unit test.
|
||||
|
||||
/**
|
||||
* Unquotes given Quoted-Printable value. value must not be null.
|
||||
*/
|
||||
public static String parseQuotedPrintable(
|
||||
final String value, boolean strictLineBreaking,
|
||||
String sourceCharset, String targetCharset) {
|
||||
// "= " -> " ", "=\t" -> "\t".
|
||||
// Previous code had done this replacement. Keep on the safe side.
|
||||
final String quotedPrintable;
|
||||
{
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final int length = value.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char ch = value.charAt(i);
|
||||
if (ch == '=' && i < length - 1) {
|
||||
char nextCh = value.charAt(i + 1);
|
||||
if (nextCh == ' ' || nextCh == '\t') {
|
||||
builder.append(nextCh);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
builder.append(ch);
|
||||
}
|
||||
quotedPrintable = builder.toString();
|
||||
}
|
||||
|
||||
String[] lines;
|
||||
if (strictLineBreaking) {
|
||||
lines = quotedPrintable.split("\r\n");
|
||||
} else {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
final int length = quotedPrintable.length();
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char ch = quotedPrintable.charAt(i);
|
||||
if (ch == '\n') {
|
||||
list.add(builder.toString());
|
||||
builder = new StringBuilder();
|
||||
} else if (ch == '\r') {
|
||||
list.add(builder.toString());
|
||||
builder = new StringBuilder();
|
||||
if (i < length - 1) {
|
||||
char nextCh = quotedPrintable.charAt(i + 1);
|
||||
if (nextCh == '\n') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
final String lastLine = builder.toString();
|
||||
if (lastLine.length() > 0) {
|
||||
list.add(lastLine);
|
||||
}
|
||||
lines = list.toArray(new String[0]);
|
||||
}
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
if (line.endsWith("=")) {
|
||||
line = line.substring(0, line.length() - 1);
|
||||
}
|
||||
builder.append(line);
|
||||
}
|
||||
|
||||
final String rawString = builder.toString();
|
||||
if (TextUtils.isEmpty(rawString)) {
|
||||
Log.w(LOG_TAG, "Given raw string is empty.");
|
||||
}
|
||||
|
||||
byte[] rawBytes = null;
|
||||
try {
|
||||
rawBytes = rawString.getBytes(sourceCharset);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.w(LOG_TAG, "Failed to decode: " + sourceCharset);
|
||||
rawBytes = rawString.getBytes();
|
||||
}
|
||||
|
||||
byte[] decodedBytes = null;
|
||||
try {
|
||||
decodedBytes = QuotedPrintableCodecPort.decodeQuotedPrintable(rawBytes);
|
||||
} catch (DecoderException e) {
|
||||
Log.e(LOG_TAG, "DecoderException is thrown.");
|
||||
decodedBytes = rawBytes;
|
||||
}
|
||||
|
||||
try {
|
||||
return new String(decodedBytes, targetCharset);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
|
||||
return new String(decodedBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static final VCardParser getAppropriateParser(int vcardType)
|
||||
throws VCardException {
|
||||
if (VCardConfig.isVersion21(vcardType)) {
|
||||
return new VCardParser_V21();
|
||||
} else if (VCardConfig.isVersion30(vcardType)) {
|
||||
return new VCardParser_V30();
|
||||
} else if (VCardConfig.isVersion40(vcardType)) {
|
||||
return new VCardParser_V40();
|
||||
} else {
|
||||
throw new VCardException("Version is not specified");
|
||||
}
|
||||
}
|
||||
|
||||
public static final String convertStringCharset(
|
||||
String originalString, String sourceCharset, String targetCharset) {
|
||||
if (sourceCharset.equalsIgnoreCase(targetCharset)) {
|
||||
return originalString;
|
||||
}
|
||||
final Charset charset = Charset.forName(sourceCharset);
|
||||
final ByteBuffer byteBuffer = charset.encode(originalString);
|
||||
// byteBuffer.array() "may" return byte array which is larger than
|
||||
// byteBuffer.remaining(). Here, we keep on the safe side.
|
||||
final byte[] bytes = new byte[byteBuffer.remaining()];
|
||||
byteBuffer.get(bytes);
|
||||
try {
|
||||
return new String(bytes, targetCharset);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: utilities for vCard 4.0: datetime, timestamp, integer, float, and boolean
|
||||
|
||||
private VCardUtils() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.exception;
|
||||
|
||||
public class VCardAgentNotSupportedException extends VCardNotSupportedException {
|
||||
public VCardAgentNotSupportedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public VCardAgentNotSupportedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.exception;
|
||||
|
||||
public class VCardException extends java.lang.Exception {
|
||||
/**
|
||||
* Constructs a VCardException object
|
||||
*/
|
||||
public VCardException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a VCardException object
|
||||
*
|
||||
* @param message the error message
|
||||
*/
|
||||
public VCardException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.exception;
|
||||
|
||||
/**
|
||||
* Thrown when the vCard has some line starting with '#'. In the specification,
|
||||
* both vCard 2.1 and vCard 3.0 does not allow such line, but some actual exporter emit
|
||||
* such lines.
|
||||
*/
|
||||
public class VCardInvalidCommentLineException extends VCardInvalidLineException {
|
||||
public VCardInvalidCommentLineException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public VCardInvalidCommentLineException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.exception;
|
||||
|
||||
/**
|
||||
* Thrown when the vCard has some line starting with '#'. In the specification,
|
||||
* both vCard 2.1 and vCard 3.0 does not allow such line, but some actual exporter emit
|
||||
* such lines.
|
||||
*/
|
||||
public class VCardInvalidLineException extends VCardException {
|
||||
public VCardInvalidLineException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public VCardInvalidLineException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.exception;
|
||||
|
||||
/**
|
||||
* VCardException thrown when VCard is nested without VCardParser's being notified.
|
||||
*/
|
||||
public class VCardNestedException extends VCardNotSupportedException {
|
||||
public VCardNestedException() {
|
||||
super();
|
||||
}
|
||||
public VCardNestedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.exception;
|
||||
|
||||
/**
|
||||
* The exception which tells that the input VCard is probably valid from the view of
|
||||
* specification but not supported in the current framework for now.
|
||||
*
|
||||
* This is a kind of a good news from the view of development.
|
||||
* It may be good to ask users to send a report with the VCard example
|
||||
* for the future development.
|
||||
*/
|
||||
public class VCardNotSupportedException extends VCardException {
|
||||
public VCardNotSupportedException() {
|
||||
super();
|
||||
}
|
||||
public VCardNotSupportedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.exception;
|
||||
|
||||
/**
|
||||
* VCardException used only when the version of the vCard is different.
|
||||
*/
|
||||
public class VCardVersionException extends VCardException {
|
||||
public VCardVersionException() {
|
||||
super();
|
||||
}
|
||||
public VCardVersionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2010 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package {
|
||||
default_team: "trendy_team_pixel_connectivity_bt",
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "AndroidVCardTests",
|
||||
|
||||
certificate: "platform",
|
||||
platform_apis: true,
|
||||
test_suites: ["device-tests"],
|
||||
srcs: ["src/**/*.java"],
|
||||
libs: [
|
||||
"android.test.runner.stubs.system",
|
||||
"android.test.base.stubs.system",
|
||||
"android.test.mock.stubs.system",
|
||||
],
|
||||
static_libs: [
|
||||
"com.android.vcard",
|
||||
"junit",
|
||||
"androidx.test.ext.truth",
|
||||
"androidx.test.rules",
|
||||
"mockito-target",
|
||||
"truth",
|
||||
],
|
||||
|
||||
jacoco: {
|
||||
include_filter: ["com.android.vcard.*"],
|
||||
exclude_filter: ["com.android.vcard.tests.*"],
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Run test with:
|
||||
adb shell am instrument -w com.android.vcard.tests/android.test.InstrumentationTestRunner
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.vcard.tests"
|
||||
android:sharedUserId="com.android.uid.test">
|
||||
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="android.test.InstrumentationTestRunner"
|
||||
android:targetPackage="com.android.vcard.tests"
|
||||
android:label="TestRunner letting users run each test including new one" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<configuration description="TestRunner letting users run each test including new one.">
|
||||
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
|
||||
<option name="test-file-name" value="AndroidVCardTests.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-tag" value="AndroidVCardTests" />
|
||||
<test class="com.android.tradefed.testtype.InstrumentationTest" >
|
||||
<option name="package" value="com.android.vcard.tests" />
|
||||
<option name="runner" value="android.test.InstrumentationTestRunner" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
||||
@@ -0,0 +1,10 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:bogus
|
||||
URL:http://bogus.com/
|
||||
ADR;HOME:;;Grindelberg 999;Hamburg;;99999;Deutschland
|
||||
ADR;HOME:;;Hermann v. Brevern\
|
||||
9999999\
|
||||
Packstation 999;Hamburg;;99999;Deutschland
|
||||
BDAY;VALUE=DATE:20081203
|
||||
END:VCARD
|
||||
@@ -0,0 +1,6 @@
|
||||
BEGIN:VCARD
|
||||
X-ANDROID-CUSTOM:custom_mime1;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15
|
||||
X-ANDROID-CUSTOM:custom_mime2;a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p
|
||||
X-ANDROID-CUSTOM:custom_mime3
|
||||
X-ANDROID-CUSTOM:custom_mime4;z
|
||||
END:VCARD
|
||||
@@ -0,0 +1,5 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:;A\;B\\;C\\\;;D;\:E;\\\\;
|
||||
FN:A;B\C\;D:E\\
|
||||
END:VCARD
|
||||
@@ -0,0 +1,78 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:name
|
||||
FN:fullname
|
||||
PHOTO;ENCODING=BASE64;TYPE=JPEG:
|
||||
/9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG
|
||||
AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx
|
||||
AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB
|
||||
AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI
|
||||
AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg
|
||||
ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ
|
||||
gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA
|
||||
AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA
|
||||
AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA
|
||||
kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA
|
||||
AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK
|
||||
knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA
|
||||
AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw
|
||||
ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA
|
||||
AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA
|
||||
pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA
|
||||
AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1
|
||||
OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA
|
||||
AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA
|
||||
AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA
|
||||
ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA
|
||||
AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww
|
||||
YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe
|
||||
xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG
|
||||
/8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA
|
||||
AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
|
||||
FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
|
||||
h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
|
||||
5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH
|
||||
BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
|
||||
JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
|
||||
lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
|
||||
9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF
|
||||
ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA
|
||||
RtUbUgIWqJhQBZSpFoAlWpVoGPFPFMQ7tSK2ODQA4yKO9HmKe9FxAzDHFIOlAAaYaAGNUTUD
|
||||
ImqNqQETVE1AE6VKKAJFNSqaAHg08GmANIFFQM5Y5qJMBuT60ZNQIcrkVYSQMKuLGKaaasQx
|
||||
qiagZE1RtSAjaomoAkQ1KpoAlU1IpoAkU07OBTArO+5qkV12Y71lfUBmaKkCRSuznrTFba2a
|
||||
oCwGyM0E1qIjY1GxoGRNUZNICNqiagByGplNAEimpFNMB4YDvSucpxSYEIU04KazsAu1qArU
|
||||
WELtPpTSposBNETt5pxNaoCNjUbGgCNjUZoGRtUTUgFU1KpoAkBqQHigCFnO7rUqOdlZp6gA
|
||||
c+tODn1pXAXzD60eYfWncQvmNSGQ07gOMhCVEJGz1ptgS5yKYxqwGE1GxoAiamGkMapqVTQB
|
||||
Kpp+eKAICfmqWM/Kaz6gANOBqQFzRmmAuaTNACsfkqMHmm9wJs8U0mtRDGNRsaAI2phpDI1N
|
||||
SqaAJFNSA8UCISfmqSM/Kaz6jAHmnA1ICg0uaAFzSZpgKx+SmDrTe4E2eKaTWoiMmmMaAIzT
|
||||
DSGRKakU0ASKaeDTERseakjPyms+oxAacDUgOBpc0gFzSZpgOY/KKYv3qrqIlpprQBjGoyaA
|
||||
GGmmkMgU1IppgPBqQGgQu0Gn4wvFKwEQpwNZDHZpc0ALmigRKBleaQKBWtgA001QDGqM0gGm
|
||||
mGkMrqakBoAepp4NMRIDTwaAE2A008GokgHxjd1pzKFpW0uAg5NSBBTirgOpDWgDTTTQAw0w
|
||||
0gGGmmgZWBp4pASKaeDTEOBp4NADwajbrUyBEkXWnSUdAGr1qeiAMSkNWAhphoAaaYaQDDTT
|
||||
SGVRTwaYDxTwaBDwaeDQA4GlK5oauIeo20pGaLaAKqgU6hKwBSGmAhphoAaaYaQxhpppDKgN
|
||||
PFMB4p4oEPFOBpgPBp4NAhwpwoAWloAKSgBDTTQMYaYaQDTTTSGA/9n/2wCEAAoHBwgHBgoI
|
||||
CAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9
|
||||
PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7
|
||||
Ozs7Ozs7Ozs7Ozs7O//AABEIAEgAYAMBIQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAA
|
||||
AQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNC
|
||||
scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp
|
||||
anN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
|
||||
09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI
|
||||
CQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVi
|
||||
ctEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4
|
||||
eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY
|
||||
2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AJ7SLgcVr20I4rNFGvbQAAHFaEUX
|
||||
SrQi5HCMdKk8oY6VSJYx4hjpVaWMelAFC4iGDxWPdR8mkxmRdxjBrEvI+tZjN20xtHNbNqAc
|
||||
UIDXg6Cr0WKtCY8XKQOyzOB3FKNWsyceZ+lS6sY6NkjvPSdwImBHUmmy4q076oCjOODWPdgc
|
||||
0MpGPdAYNYl4o5rNjNKzkyorZtXxihAa1vIDip7m9Frb7/4jwKcnyxbEzN3ieJppZsyZ4U1H
|
||||
urzZau4mWVlNrGk0UuWPVa1YroXEIkHfrXZh5W90RWncAHmsi6bJNdQ0ZNw3BrGuiMGs2Mks
|
||||
puBzWzbzdOaEBeOpR2oUtkk9hTru7iuo4m8wgemKyqTi04sBsfkEf68j8KlUQZz9o/SuZRj3
|
||||
JYriAji4/Sp7W6htbV2aXcu70ramoxle4gN7HcIXjbis+4k5NdaaauhmVcv1rHuW61DGiG1m
|
||||
6c1s20/TmgAv5vmj57VKk3+ixnPc1xVV70h9CVJuOtSrL71hFgxzScUkkn+iY/2q1i9xDrGT
|
||||
9y31pJ5Otd1L+GhMy7mTrWXO2SapjRn28vTmta3nxjmgGOvJd2w1Kkv+ipz/ABGuOoveYdCe
|
||||
ObjrU6y5rlsA8ycUksn+ij/eNaw6iJLNsW59zTJn6816FP4EJmbO+Saz5m602UjIgk4HNadv
|
||||
LwKaBl+MpIMOMipp490SCJeF7CoqQvF2JuRqWQ4YEGrSiQJuKnHrXByMpki73GFBNXIoh9n2
|
||||
SrnnOK6MPTbd3sSwIVF2qMCqkzHmuy1lYRnTHrVGWpZaMKB+BWlbycYoQM0IZDxzV+GU8c1a
|
||||
IYy5Y+dnHatAsfsAHfArmS1mPoh1gT8x9qtk1rQX7tCe5DIapzGtGBQm71SlqGWjnIH6Vowt
|
||||
zmhAy/E3vV6F6tEMuxlWIyAfrVxCCAO1VZEEyYA4AApxNGwyJ+lVJRUsaKMw61SlFQzRAP/Z
|
||||
END:VCARD
|
||||
@@ -0,0 +1,44 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
FN:boogie
|
||||
N:boogie
|
||||
PHOTO;ENCODING=BASE64:iVBORw0KGgoAAAANSUhEUgAAADIAAAA6CAYAAAGFazpKAAAAGXRFWHRTb
|
||||
2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAB6pJREFUeNpi/P//PwMUgBiMDEiABcaYtFeCgY2
|
||||
F9/+//78ZshweMCJL/udml0DWBDYFJPn/+N12ht9/vyJLMjx+f/g/EwMeAJJktFSuxJCQFbRlhOlkB
|
||||
Dkkw/42TA7iapBXoBgEGH7/+fYfJgYQQIxI/mTA5sf/Mw6qghlQYxnBOuYeMUDRlmxzgZFx+gGV/7i
|
||||
cjt1PSE6FA7AYzHkgIyftlfoPczpcAuoHuD8AAgjZk2B87E7bf2Sw80r2f3Q1KJ4HxuV/RkZmBi42U
|
||||
XDsgILSUDad4eKTeXC/w3zzf/I+6f9//n7/z8LMwcDMxMrw888HsAYQOP94JpwNDDyIOhCHlZmL4fS
|
||||
DCQxMjKwMhMDzT2cQ4SbErc5ADBDiUkXx039o+gRzfv35jMLOc36B4id4mgFKMP7++w3MASlCZiPnB
|
||||
IAAQk86GNkEXQwjHYBCBqoIhrGmQTB49/U2w9KTDuBQBAFQELOzCICSHtaU9n/VGS+GaPMDcAFnjT5
|
||||
wxN58se4/hh+AefL/tecrsQYrSBMwBUByN0jh6QcTGUwV8sGxjg38+fuDYckJu//vvt5iYAGlH1i44
|
||||
4p5RsbfDO+/3QWrY2IgEvz//xd/9sKZ7ViZuYlSCErdsFD6Dw0lcH7AHkrfGHKdniIKKxBWlwgBJzZ
|
||||
YhMHYIMWgfANTh559/4My/o3na/+jseFqSPY0RgHx9ssteAmCzIZhgADC0IDuRKQSBqeaxcdt8arBW
|
||||
fwi5R9QIQIOPFCyAkUJiAYBUAWjJRnOAK0VGHEZgsuS/6AsteK0K8Pff7/BUbf6rC8wKG6gKIq1OMz
|
||||
w7ttthq2XkhhA6Qaa3RiJseQ/sFYDayQVIKUlRmyW/EcrRaCplZNkNnLhIsStCi914LUeCOjLQHyAK
|
||||
+UT4xNghQEvubz15pGRfskANLEEVuzQ1BKsPgHVwjzskgxKIu4M2FpCpAJQhQYyy1G9E9SKAkc8OLn
|
||||
FWBxCyYAUAkY37SmEMyOMMe2AAryeALlMXSIIzEZOQcji2DIjrjhhxFdM4PMBWalLlFcXngdkBK3gB
|
||||
knwG6GL4wQAAURMAUnIR//x+YKQT/7vuppDKCH8BzYp4MUK0RUQel2x6ozPf3wASZ6B7PoE5FJQGxT
|
||||
U2gDlZFCLFwZAFTKwF8NAKLjwWfIf2O5h+PTjEbhOgSVX9AIRZHGg0WpwpiM1df0Hdj0Yvvx8Dm7OZ
|
||||
drfgTe1YQBUSYFKXFBbavPFWHDRjiv+mHAFEax79vDtPnBTHB2AWn5ff74AWw7KrEtO2JKUhP8j52Z
|
||||
SAKjuwBZsLNgUgywgtq2HDJ68OwKzBMMn/2FVLnL1SWkVjFT9grvI4I41qKkDKkJCjTfD+aQAUApUF
|
||||
w9kcNLoZph+UAUcGsI8GiDz/rOAbIS1yp9/OI1IEUT0zVBSEDNE/d3X2+Hx+eLjOczUhZzRaFbHQ5v
|
||||
Ug78hwcUuSp/WyjC2hB2YfGGFH6xLQAkAjR4glxxgS0B9DNAoCKjdFQPsClAKQOaBWi+gdhds9Adrq
|
||||
x556IIUADIYub0Fy34sWGo1qjTuCJbCIC+D6gpQCYBc5MP6wrjENaXCSevOQccR4T0upFEeFHHoaCX
|
||||
eBh4TKS1BIoKIkWr55NvP10Msx4OqUlikIg0KM4Ja8DBx0EgWyUMY6C1I0KDoo3eH0FuJuMSxYoAA7
|
||||
ZpNS1tBFIYnIbShxU9oqWi1oCBVKC6SjRW6U7vsRvwRCsW12/6CQhf+AimCXRQRoSvBjYuKpWLAjeD
|
||||
Cj4UfwaK2YPuMnGFyM9f7lcSkeOByQzLJve/cOee87zsJYpC3kmyW+cNMi/T1VMzZNL9lz1ZNizCOx
|
||||
9zqS5s8Rj4AAFndO15LVmFiPhEzk7Ct+fUx1fvkrdbN1AIoXvHixq07vdjV55Zsjz43ZTtVV/uI6mj
|
||||
OafK78nNaTeaXEz2NJEAMCIQLJq34rmHJmnRJkux524h63TebCExUICWVGQEkxJybYfaPij8CwQCiO
|
||||
dutnja9UofFTS2yZBIsVRAJUBQg7GOoxY0JTW/tfjWRWzLeGWK5cLDoK20AIZxeknx+fdzoLSYHe+D
|
||||
d0OdIRSQsEF8QcnHek+USZnnZ3/GOjwMmHXY5ITgQLlB+Lm4f8p4960GH/R3XZ1yLa4alTinPBqpvB
|
||||
PomVQpbv95GdozoJdgA2TtZU5e/T3Ui2pWEz6wZqnpc/jmz7X/dq75tz+higvZl6WGS2L52WcIRuCn
|
||||
b+wtqbPCTcRXZuopDv+MEHEh6EVXyy/dJnVPkE/qaLQkMFvQHYNI36Itlm+ime58X7mRJ2Rofmuq1y
|
||||
mXM+dV+abLTC7w+ViNFWv0n0RBAXObJ/RNpGCBUrag2Y90BoQ6zL3qly/Avs7nf0ZpX+Rfv7/wmYcP
|
||||
8RUPuj4PXuZ4pw5R9d5O91IDOzn8+atUQuVmca4eP5Ww7GacXVQriuk5WT6ohk93VySuiR4S4Ff7xL
|
||||
zgQ2pvzztHXsiIh4qmrdbhkLOESXa7x6PooSjGW1JWAzLEF5wVCItpkU4Kdt5WtaacwGx34WDY+itT
|
||||
NxFynsfKGDh1yydTW10rKauumsz9+8Kxi48PwqaoadLZyI7B53vR/cCXqtUvptT3q9RtfMyBBfSZVo
|
||||
fGh4i/V4q4YNEfoiwAAAABJRU5ErkJggg==
|
||||
TEL;TYPE=WORK:+5555555
|
||||
TEL;TYPE=CELL:+5555556
|
||||
EMAIL;TYPE=INTERNET:forrestgump@walladalla.com
|
||||
END:VCARD
|
||||
@@ -0,0 +1,107 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:Gump;Forrest;Hoge;Pos;Tao
|
||||
FN:Joe Due
|
||||
ORG:Gump Shrimp Co.;Sales Dept.\;Manager;Fish keeper
|
||||
ROLE:Fish Cake Keeper!
|
||||
X-CLASS:PUBLIC
|
||||
TITLE:Shrimp Man
|
||||
TEL;WORK;VOICE:(111) 555-1212
|
||||
TEL;HOME;VOICE:(404) 555-1212
|
||||
TEL;FAX:(404) 555-1212P*#55
|
||||
TEL;CELL:0311111111
|
||||
TEL;VIDEO:0322222222
|
||||
TEL;VOICE:0333333333
|
||||
ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
|
||||
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited States of America
|
||||
ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
|
||||
LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0A=
|
||||
Baytown, LA 30314=0D=0A=
|
||||
United States of America
|
||||
EMAIL;PREF;INTERNET:forrestgump@walladalla.com
|
||||
EMAIL;CELL:cell@example.com
|
||||
NOTE:The following note is the example from RFC 2045.
|
||||
NOTE;ENCODING=QUOTED-PRINTABLE:Now's the time =
|
||||
for all folk to come=
|
||||
to the aid of their country.
|
||||
|
||||
PHOTO;ENCODING=BASE64;TYPE=JPEG:
|
||||
/9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG
|
||||
AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx
|
||||
AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB
|
||||
AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI
|
||||
AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg
|
||||
ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ
|
||||
gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA
|
||||
AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA
|
||||
AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA
|
||||
kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA
|
||||
AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK
|
||||
knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA
|
||||
AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw
|
||||
ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA
|
||||
AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA
|
||||
pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA
|
||||
AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1
|
||||
OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA
|
||||
AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA
|
||||
AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA
|
||||
ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA
|
||||
AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww
|
||||
YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe
|
||||
xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG
|
||||
/8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA
|
||||
AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
|
||||
FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
|
||||
h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
|
||||
5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH
|
||||
BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
|
||||
JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
|
||||
lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
|
||||
9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF
|
||||
ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA
|
||||
RtUbUgIWqJhQBZSpFoAlWpVoGPFPFMQ7tSK2ODQA4yKO9HmKe9FxAzDHFIOlAAaYaAGNUTUD
|
||||
ImqNqQETVE1AE6VKKAJFNSqaAHg08GmANIFFQM5Y5qJMBuT60ZNQIcrkVYSQMKuLGKaaasQx
|
||||
qiagZE1RtSAjaomoAkQ1KpoAlU1IpoAkU07OBTArO+5qkV12Y71lfUBmaKkCRSuznrTFba2a
|
||||
oCwGyM0E1qIjY1GxoGRNUZNICNqiagByGplNAEimpFNMB4YDvSucpxSYEIU04KazsAu1qArU
|
||||
WELtPpTSposBNETt5pxNaoCNjUbGgCNjUZoGRtUTUgFU1KpoAkBqQHigCFnO7rUqOdlZp6gA
|
||||
c+tODn1pXAXzD60eYfWncQvmNSGQ07gOMhCVEJGz1ptgS5yKYxqwGE1GxoAiamGkMapqVTQB
|
||||
Kpp+eKAICfmqWM/Kaz6gANOBqQFzRmmAuaTNACsfkqMHmm9wJs8U0mtRDGNRsaAI2phpDI1N
|
||||
SqaAJFNSA8UCISfmqSM/Kaz6jAHmnA1ICg0uaAFzSZpgKx+SmDrTe4E2eKaTWoiMmmMaAIzT
|
||||
DSGRKakU0ASKaeDTERseakjPyms+oxAacDUgOBpc0gFzSZpgOY/KKYv3qrqIlpprQBjGoyaA
|
||||
GGmmkMgU1IppgPBqQGgQu0Gn4wvFKwEQpwNZDHZpc0ALmigRKBleaQKBWtgA001QDGqM0gGm
|
||||
mGkMrqakBoAepp4NMRIDTwaAE2A008GokgHxjd1pzKFpW0uAg5NSBBTirgOpDWgDTTTQAw0w
|
||||
0gGGmmgZWBp4pASKaeDTEOBp4NADwajbrUyBEkXWnSUdAGr1qeiAMSkNWAhphoAaaYaQDDTT
|
||||
SGVRTwaYDxTwaBDwaeDQA4GlK5oauIeo20pGaLaAKqgU6hKwBSGmAhphoAaaYaQxhpppDKgN
|
||||
PFMB4p4oEPFOBpgPBp4NAhwpwoAWloAKSgBDTTQMYaYaQDTTTSGA/9n/2wCEAAoHBwgHBgoI
|
||||
CAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9
|
||||
PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7
|
||||
Ozs7Ozs7Ozs7Ozs7O//AABEIAEgAYAMBIQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAA
|
||||
AQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNC
|
||||
scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp
|
||||
anN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
|
||||
09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI
|
||||
CQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVi
|
||||
ctEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4
|
||||
eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY
|
||||
2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AJ7SLgcVr20I4rNFGvbQAAHFaEUX
|
||||
SrQi5HCMdKk8oY6VSJYx4hjpVaWMelAFC4iGDxWPdR8mkxmRdxjBrEvI+tZjN20xtHNbNqAc
|
||||
UIDXg6Cr0WKtCY8XKQOyzOB3FKNWsyceZ+lS6sY6NkjvPSdwImBHUmmy4q076oCjOODWPdgc
|
||||
0MpGPdAYNYl4o5rNjNKzkyorZtXxihAa1vIDip7m9Frb7/4jwKcnyxbEzN3ieJppZsyZ4U1H
|
||||
urzZau4mWVlNrGk0UuWPVa1YroXEIkHfrXZh5W90RWncAHmsi6bJNdQ0ZNw3BrGuiMGs2Mks
|
||||
puBzWzbzdOaEBeOpR2oUtkk9hTru7iuo4m8wgemKyqTi04sBsfkEf68j8KlUQZz9o/SuZRj3
|
||||
JYriAji4/Sp7W6htbV2aXcu70ramoxle4gN7HcIXjbis+4k5NdaaauhmVcv1rHuW61DGiG1m
|
||||
6c1s20/TmgAv5vmj57VKk3+ixnPc1xVV70h9CVJuOtSrL71hFgxzScUkkn+iY/2q1i9xDrGT
|
||||
9y31pJ5Otd1L+GhMy7mTrWXO2SapjRn28vTmta3nxjmgGOvJd2w1Kkv+ipz/ABGuOoveYdCe
|
||||
ObjrU6y5rlsA8ycUksn+ij/eNaw6iJLNsW59zTJn6816FP4EJmbO+Saz5m602UjIgk4HNadv
|
||||
LwKaBl+MpIMOMipp490SCJeF7CoqQvF2JuRqWQ4YEGrSiQJuKnHrXByMpki73GFBNXIoh9n2
|
||||
SrnnOK6MPTbd3sSwIVF2qMCqkzHmuy1lYRnTHrVGWpZaMKB+BWlbycYoQM0IZDxzV+GU8c1a
|
||||
IYy5Y+dnHatAsfsAHfArmS1mPoh1gT8x9qtk1rQX7tCe5DIapzGtGBQm71SlqGWjnIH6Vowt
|
||||
zmhAy/E3vV6F6tEMuxlWIyAfrVxCCAO1VZEEyYA4AApxNGwyJ+lVJRUsaKMw61SlFQzRAP/Z
|
||||
|
||||
X-ATTRIBUTE:Some String
|
||||
BDAY:19800101
|
||||
GEO:35.6563854,139.6994233
|
||||
URL:http://www.example.com/
|
||||
REV:20080424T195243Z
|
||||
END:VCARD
|
||||
@@ -0,0 +1,5 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
X-ANDROID-CUSTOM:vnd.android.cursor.item/nickname;Nick;1;;;;;;;;;;;;;
|
||||
X-GOOGLE-TALK:hhh@gmail.com
|
||||
END:VCARD
|
||||
@@ -0,0 +1,10 @@
|
||||
BEGIN:vCard
|
||||
VERSION:2.1
|
||||
UID:357
|
||||
N:;Conference Call
|
||||
FN:Conference Call
|
||||
# This line must be ignored.
|
||||
NOTE;ENCODING=QUOTED-PRINTABLE:This is an (sharp ->=
|
||||
#<- sharp) example. This message must NOT be ignored.
|
||||
# This line must be ignored too.
|
||||
END:vCard
|
||||
@@ -0,0 +1,7 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:;Omega;;;
|
||||
EMAIL;INTERNET:"Omega"
|
||||
<omega@example.com>
|
||||
FN:Omega
|
||||
END:VCARD
|
||||
@@ -0,0 +1,6 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N;CHARSET=SHIFT_JIS:安藤ロイド;;;;
|
||||
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウロイド;;;;
|
||||
TEL;PREF;VOICE:0300000000
|
||||
END:VCARD
|
||||
@@ -0,0 +1,10 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
FN;CHARSET=SHIFT_JIS:安藤 ロイド 1
|
||||
N;CHARSET=SHIFT_JIS:安藤;ロイド1;;;
|
||||
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウ;ロイド1;;;
|
||||
ADR;HOME;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:;=93=8C=8B=9E=93=73=
|
||||
=8F=61=92=4A=8B=E6=8D=F7=8B=75=92=AC26-1=83=5A=83=8B=83=8A=83=41=83=93=
|
||||
=83=5E=83=8F=81=5B6=8A=4B;;;;150-8512;
|
||||
NOTE;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:=83=81=83=82
|
||||
END:VCARD
|
||||
@@ -0,0 +1,5 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
FN;CHARSET=SHIFT_JIS:ˆÉ”\ Œ\ˆê ˆÉ—\
|
||||
N;CHARSET=SHIFT_JIS:ˆÉ”\;Œ\ˆê;ˆÉ—\;;
|
||||
END:VCARD
|
||||
@@ -0,0 +1,7 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:name
|
||||
FN:fullname
|
||||
PHOTO;ENCODING=BASE64;TYPE=JPEG:qgEPAAIAAAAHAAAAugEQAAIAAAAG:ASDF==
|
||||
|
||||
END:VCARD
|
||||
@@ -0,0 +1,33 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N;CHARSET=SHIFT_JIS:安藤ロイド3;;;;
|
||||
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウロイド3;;;;
|
||||
TEL;X-NEC-SECRET:9
|
||||
TEL;X-NEC-HOTEL:10
|
||||
TEL;X-NEC-SCHOOL:11
|
||||
TEL;HOME;FAX:12
|
||||
END:VCARD
|
||||
|
||||
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N;CHARSET=SHIFT_JIS:安藤ロイド4;;;;
|
||||
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウロイド4;;;;
|
||||
TEL;MODEM:13
|
||||
TEL;PAGER:14
|
||||
TEL;X-NEC-FAMILY:15
|
||||
TEL;X-NEC-GIRL:16
|
||||
END:VCARD
|
||||
|
||||
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N;CHARSET=SHIFT_JIS:安藤ロイド5;;;;
|
||||
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウロイド5;;;;
|
||||
TEL;X-NEC-BOY:17
|
||||
TEL;X-NEC-FRIEND:18
|
||||
TEL;X-NEC-PHS:19
|
||||
TEL;X-NEC-RESTAURANT:20
|
||||
END:VCARD
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:parent
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:nest1
|
||||
END:VCARD
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:nest2
|
||||
END:VCARD
|
||||
TEL:1
|
||||
END:VCARD
|
||||
@@ -0,0 +1,16 @@
|
||||
Content-Type: text/x-vcard
|
||||
CHARSET=utf-8
|
||||
profile=vCard
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:parent
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:nest1
|
||||
END:VCARD
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:nest2
|
||||
END:VCARD
|
||||
TEL:1
|
||||
END:VCARD
|
||||
@@ -0,0 +1,6 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
FN:Normal Guy
|
||||
ORG:Company;Organization;Devision;Room;Sheet No.
|
||||
TITLE:Excellent Janitor
|
||||
END:VCARD
|
||||
@@ -0,0 +1,15 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
FN:Smith
|
||||
TEL;HOME:1
|
||||
TEL;WORK;PREF:2
|
||||
TEL;ISDN:3
|
||||
EMAIL;PREF;HOME:test@example.com
|
||||
EMAIL;CELL;PREF:test2@examination.com
|
||||
ORG:Company
|
||||
TITLE:Engineer
|
||||
ORG:Mystery
|
||||
TITLE:Blogger
|
||||
ORG:Poetry
|
||||
TITLE:Poet
|
||||
END:VCARD
|
||||
@@ -0,0 +1,3 @@
|
||||
BEGIN:VCARD
|
||||
N:Ando;Roid;
|
||||
END:VCARD
|
||||
@@ -0,0 +1,3 @@
|
||||
BEGIN:VCARD
|
||||
FN:Ando Roid
|
||||
END:VCARD
|
||||
@@ -0,0 +1,4 @@
|
||||
BEGIN:VCARD
|
||||
N:Ando;Roid;
|
||||
FN:Ando Roid
|
||||
END:VCARD
|
||||
@@ -0,0 +1,6 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
FN:Android
|
||||
X-SIP:888
|
||||
X-SIP:sip:90-180-360
|
||||
END:VCARD
|
||||
@@ -0,0 +1,6 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
FN:Nice Guy
|
||||
TITLE:Cool Title
|
||||
ORG:Marverous;Perfect;Great;Good;Bad;Poor
|
||||
END:VCARD
|
||||
@@ -0,0 +1,10 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:Example;;;;
|
||||
FN:Example
|
||||
ANNIVERSARY;VALUE=DATE:20091010
|
||||
AGENT:Invalid line which must be handled correctly.
|
||||
X-CLASS:PUBLIC
|
||||
X-REDUCTION:
|
||||
X-NO:
|
||||
END:VCARD
|
||||
@@ -0,0 +1,42 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:Ando;Roid;
|
||||
PHOTO;ENCODING=BASE64:iVBORw0KGgoAAAANSUhEUgAAADIAAAA6CAYAAAGFazpKAAAAGXRFWHRTb
|
||||
2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAB6pJREFUeNpi/P//PwMUgBiMDEiABcaYtFeCgY2
|
||||
F9/+//78ZshweMCJL/udml0DWBDYFJPn/+N12ht9/vyJLMjx+f/g/EwMeAJJktFSuxJCQFbRlhOlkB
|
||||
Dkkw/42TA7iapBXoBgEGH7/+fYfJgYQQIxI/mTA5sf/Mw6qghlQYxnBOuYeMUDRlmxzgZFx+gGV/7i
|
||||
cjt1PSE6FA7AYzHkgIyftlfoPczpcAuoHuD8AAgjZk2B87E7bf2Sw80r2f3Q1KJ4HxuV/RkZmBi42U
|
||||
XDsgILSUDad4eKTeXC/w3zzf/I+6f9//n7/z8LMwcDMxMrw888HsAYQOP94JpwNDDyIOhCHlZmL4fS
|
||||
DCQxMjKwMhMDzT2cQ4SbErc5ADBDiUkXx039o+gRzfv35jMLOc36B4id4mgFKMP7++w3MASlCZiPnB
|
||||
IAAQk86GNkEXQwjHYBCBqoIhrGmQTB49/U2w9KTDuBQBAFQELOzCICSHtaU9n/VGS+GaPMDcAFnjT5
|
||||
wxN58se4/hh+AefL/tecrsQYrSBMwBUByN0jh6QcTGUwV8sGxjg38+fuDYckJu//vvt5iYAGlH1i44
|
||||
4p5RsbfDO+/3QWrY2IgEvz//xd/9sKZ7ViZuYlSCErdsFD6Dw0lcH7AHkrfGHKdniIKKxBWlwgBJzZ
|
||||
YhMHYIMWgfANTh559/4My/o3na/+jseFqSPY0RgHx9ssteAmCzIZhgADC0IDuRKQSBqeaxcdt8arBW
|
||||
fwi5R9QIQIOPFCyAkUJiAYBUAWjJRnOAK0VGHEZgsuS/6AsteK0K8Pff7/BUbf6rC8wKG6gKIq1OMz
|
||||
w7ttthq2XkhhA6Qaa3RiJseQ/sFYDayQVIKUlRmyW/EcrRaCplZNkNnLhIsStCi914LUeCOjLQHyAK
|
||||
+UT4xNghQEvubz15pGRfskANLEEVuzQ1BKsPgHVwjzskgxKIu4M2FpCpAJQhQYyy1G9E9SKAkc8OLn
|
||||
FWBxCyYAUAkY37SmEMyOMMe2AAryeALlMXSIIzEZOQcji2DIjrjhhxFdM4PMBWalLlFcXngdkBK3gB
|
||||
knwG6GL4wQAAURMAUnIR//x+YKQT/7vuppDKCH8BzYp4MUK0RUQel2x6ozPf3wASZ6B7PoE5FJQGxT
|
||||
U2gDlZFCLFwZAFTKwF8NAKLjwWfIf2O5h+PTjEbhOgSVX9AIRZHGg0WpwpiM1df0Hdj0Yvvx8Dm7OZ
|
||||
drfgTe1YQBUSYFKXFBbavPFWHDRjiv+mHAFEax79vDtPnBTHB2AWn5ff74AWw7KrEtO2JKUhP8j52Z
|
||||
SAKjuwBZsLNgUgywgtq2HDJ68OwKzBMMn/2FVLnL1SWkVjFT9grvI4I41qKkDKkJCjTfD+aQAUApUF
|
||||
w9kcNLoZph+UAUcGsI8GiDz/rOAbIS1yp9/OI1IEUT0zVBSEDNE/d3X2+Hx+eLjOczUhZzRaFbHQ5v
|
||||
Ug78hwcUuSp/WyjC2hB2YfGGFH6xLQAkAjR4glxxgS0B9DNAoCKjdFQPsClAKQOaBWi+gdhds9Adrq
|
||||
x556IIUADIYub0Fy34sWGo1qjTuCJbCIC+D6gpQCYBc5MP6wrjENaXCSevOQccR4T0upFEeFHHoaCX
|
||||
eBh4TKS1BIoKIkWr55NvP10Msx4OqUlikIg0KM4Ja8DBx0EgWyUMY6C1I0KDoo3eH0FuJuMSxYoAA7
|
||||
ZpNS1tBFIYnIbShxU9oqWi1oCBVKC6SjRW6U7vsRvwRCsW12/6CQhf+AimCXRQRoSvBjYuKpWLAjeD
|
||||
Cj4UfwaK2YPuMnGFyM9f7lcSkeOByQzLJve/cOee87zsJYpC3kmyW+cNMi/T1VMzZNL9lz1ZNizCOx
|
||||
9zqS5s8Rj4AAFndO15LVmFiPhEzk7Ct+fUx1fvkrdbN1AIoXvHixq07vdjV55Zsjz43ZTtVV/uI6mj
|
||||
OafK78nNaTeaXEz2NJEAMCIQLJq34rmHJmnRJkux524h63TebCExUICWVGQEkxJybYfaPij8CwQCiO
|
||||
dutnja9UofFTS2yZBIsVRAJUBQg7GOoxY0JTW/tfjWRWzLeGWK5cLDoK20AIZxeknx+fdzoLSYHe+D
|
||||
d0OdIRSQsEF8QcnHek+USZnnZ3/GOjwMmHXY5ITgQLlB+Lm4f8p4960GH/R3XZ1yLa4alTinPBqpvB
|
||||
PomVQpbv95GdozoJdgA2TtZU5e/T3Ui2pWEz6wZqnpc/jmz7X/dq75tz+higvZl6WGS2L52WcIRuCn
|
||||
b+wtqbPCTcRXZuopDv+MEHEh6EVXyy/dJnVPkE/qaLQkMFvQHYNI36Itlm+ime58X7mRJ2Rofmuq1y
|
||||
mXM+dV+abLTC7w+ViNFWv0n0RBAXObJ/RNpGCBUrag2Y90BoQ6zL3qly/Avs7nf0ZpX+Rfv7/wmYcP
|
||||
8RUPuj4PXuZ4pw5R9d5O91IDOzn8+atUQuVmca4eP5Ww7GacXVQriuk5WT6ohk93VySuiR4S4Ff7xL
|
||||
zgQ2pvzztHXsiIh4qmrdbhkLOESXa7x6PooSjGW1JWAzLEF5wVCItpkU4Kdt5WtaacwGx34WDY+itT
|
||||
NxFynsfKGDh1yydTW10rKauumsz9+8Kxi48PwqaoadLZyI7B53vR/cCXqtUvptT3q9RtfMyBBfSZVo
|
||||
fGh4i/V4q4YNEfoiwAAAABJRU5ErkJggg==
|
||||
X-ANDROID-CUSTOM:vnd.android.cursor.item/contact_event;1999-07-10;1;;;;;;;;;;;;;
|
||||
BDAY:1975-08-20
|
||||
END:VCARD
|
||||
@@ -0,0 +1,9 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N:Ando;Roid;
|
||||
ADR;X-custom:pobox;street
|
||||
TEL;X-CuStoMpRop:1
|
||||
TEL;custompropertywithoutx:2
|
||||
EMAIL;X-cUstomPrOperty:email@example.com
|
||||
EMAIL;CUSTOMPROPERTYWITHOUTX:email2@example.com
|
||||
END:VCARD
|
||||
@@ -0,0 +1,8 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
N:Familyname;Givenname;;;
|
||||
FN:Givenname Familyname
|
||||
ADR;TYPE=WORK:;;1010 Technology Pkwy\, Silicon City\, Somecountry;;;;
|
||||
ADR;TYPE=X-Other:;;123 Main St\, Anytown\, Anywhere;;;;
|
||||
ADR;TYPE=X-School:;;112358 Academic Lane\, College Town\, Someplace Great;;;;
|
||||
END:VCARD
|
||||
@@ -0,0 +1,5 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
N;TYPE=PREF,HOME:F;G;M;;
|
||||
TEL;TYPE="COMMA,SEPARATED:INSIDE.DQUOTE",PREF:1
|
||||
END:VCARD
|
||||
@@ -0,0 +1,107 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
N:Gump;Forrest;Hoge;Pos;Tao
|
||||
FN:Joe Due
|
||||
ORG:Gump Shrimp Co.;Sales Dept.\;Manager;Fish keeper
|
||||
ROLE:Fish Cake Keeper!
|
||||
X-CLASS:PUBLIC
|
||||
TITLE:Shrimp Man
|
||||
TEL;WORK;VOICE:(111) 555-1212
|
||||
TEL;HOME;VOICE:(404) 555-1212
|
||||
TEL;FAX:(404) 555-1212P*#55
|
||||
TEL;CELL:0311111111
|
||||
TEL;VIDEO:0322222222
|
||||
TEL;VOICE:0333333333
|
||||
ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
|
||||
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited States of America
|
||||
ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
|
||||
LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0A=
|
||||
Baytown, LA 30314=0D=0A=
|
||||
United States of America
|
||||
EMAIL;PREF;INTERNET:forrestgump@walladalla.com
|
||||
EMAIL;CELL:cell@example.com
|
||||
NOTE:The following note is the example from RFC 2045.
|
||||
NOTE;ENCODING=QUOTED-PRINTABLE:Now's the time =
|
||||
for all folk to come=
|
||||
to the aid of their country.
|
||||
|
||||
PHOTO;ENCODING=BASE64;TYPE=JPEG:
|
||||
/9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG
|
||||
AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx
|
||||
AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB
|
||||
AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI
|
||||
AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg
|
||||
ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ
|
||||
gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA
|
||||
AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA
|
||||
AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA
|
||||
kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA
|
||||
AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK
|
||||
knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA
|
||||
AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw
|
||||
ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA
|
||||
AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA
|
||||
pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA
|
||||
AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1
|
||||
OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA
|
||||
AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA
|
||||
AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA
|
||||
ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA
|
||||
AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww
|
||||
YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe
|
||||
xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG
|
||||
/8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA
|
||||
AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
|
||||
FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
|
||||
h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
|
||||
5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH
|
||||
BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
|
||||
JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
|
||||
lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
|
||||
9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF
|
||||
ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA
|
||||
RtUbUgIWqJhQBZSpFoAlWpVoGPFPFMQ7tSK2ODQA4yKO9HmKe9FxAzDHFIOlAAaYaAGNUTUD
|
||||
ImqNqQETVE1AE6VKKAJFNSqaAHg08GmANIFFQM5Y5qJMBuT60ZNQIcrkVYSQMKuLGKaaasQx
|
||||
qiagZE1RtSAjaomoAkQ1KpoAlU1IpoAkU07OBTArO+5qkV12Y71lfUBmaKkCRSuznrTFba2a
|
||||
oCwGyM0E1qIjY1GxoGRNUZNICNqiagByGplNAEimpFNMB4YDvSucpxSYEIU04KazsAu1qArU
|
||||
WELtPpTSposBNETt5pxNaoCNjUbGgCNjUZoGRtUTUgFU1KpoAkBqQHigCFnO7rUqOdlZp6gA
|
||||
c+tODn1pXAXzD60eYfWncQvmNSGQ07gOMhCVEJGz1ptgS5yKYxqwGE1GxoAiamGkMapqVTQB
|
||||
Kpp+eKAICfmqWM/Kaz6gANOBqQFzRmmAuaTNACsfkqMHmm9wJs8U0mtRDGNRsaAI2phpDI1N
|
||||
SqaAJFNSA8UCISfmqSM/Kaz6jAHmnA1ICg0uaAFzSZpgKx+SmDrTe4E2eKaTWoiMmmMaAIzT
|
||||
DSGRKakU0ASKaeDTERseakjPyms+oxAacDUgOBpc0gFzSZpgOY/KKYv3qrqIlpprQBjGoyaA
|
||||
GGmmkMgU1IppgPBqQGgQu0Gn4wvFKwEQpwNZDHZpc0ALmigRKBleaQKBWtgA001QDGqM0gGm
|
||||
mGkMrqakBoAepp4NMRIDTwaAE2A008GokgHxjd1pzKFpW0uAg5NSBBTirgOpDWgDTTTQAw0w
|
||||
0gGGmmgZWBp4pASKaeDTEOBp4NADwajbrUyBEkXWnSUdAGr1qeiAMSkNWAhphoAaaYaQDDTT
|
||||
SGVRTwaYDxTwaBDwaeDQA4GlK5oauIeo20pGaLaAKqgU6hKwBSGmAhphoAaaYaQxhpppDKgN
|
||||
PFMB4p4oEPFOBpgPBp4NAhwpwoAWloAKSgBDTTQMYaYaQDTTTSGA/9n/2wCEAAoHBwgHBgoI
|
||||
CAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9
|
||||
PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7
|
||||
Ozs7Ozs7Ozs7Ozs7O//AABEIAEgAYAMBIQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAA
|
||||
AQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNC
|
||||
scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp
|
||||
anN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
|
||||
09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI
|
||||
CQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVi
|
||||
ctEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4
|
||||
eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY
|
||||
2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AJ7SLgcVr20I4rNFGvbQAAHFaEUX
|
||||
SrQi5HCMdKk8oY6VSJYx4hjpVaWMelAFC4iGDxWPdR8mkxmRdxjBrEvI+tZjN20xtHNbNqAc
|
||||
UIDXg6Cr0WKtCY8XKQOyzOB3FKNWsyceZ+lS6sY6NkjvPSdwImBHUmmy4q076oCjOODWPdgc
|
||||
0MpGPdAYNYl4o5rNjNKzkyorZtXxihAa1vIDip7m9Frb7/4jwKcnyxbEzN3ieJppZsyZ4U1H
|
||||
urzZau4mWVlNrGk0UuWPVa1YroXEIkHfrXZh5W90RWncAHmsi6bJNdQ0ZNw3BrGuiMGs2Mks
|
||||
puBzWzbzdOaEBeOpR2oUtkk9hTru7iuo4m8wgemKyqTi04sBsfkEf68j8KlUQZz9o/SuZRj3
|
||||
JYriAji4/Sp7W6htbV2aXcu70ramoxle4gN7HcIXjbis+4k5NdaaauhmVcv1rHuW61DGiG1m
|
||||
6c1s20/TmgAv5vmj57VKk3+ixnPc1xVV70h9CVJuOtSrL71hFgxzScUkkn+iY/2q1i9xDrGT
|
||||
9y31pJ5Otd1L+GhMy7mTrWXO2SapjRn28vTmta3nxjmgGOvJd2w1Kkv+ipz/ABGuOoveYdCe
|
||||
ObjrU6y5rlsA8ycUksn+ij/eNaw6iJLNsW59zTJn6816FP4EJmbO+Saz5m602UjIgk4HNadv
|
||||
LwKaBl+MpIMOMipp490SCJeF7CoqQvF2JuRqWQ4YEGrSiQJuKnHrXByMpki73GFBNXIoh9n2
|
||||
SrnnOK6MPTbd3sSwIVF2qMCqkzHmuy1lYRnTHrVGWpZaMKB+BWlbycYoQM0IZDxzV+GU8c1a
|
||||
IYy5Y+dnHatAsfsAHfArmS1mPoh1gT8x9qtk1rQX7tCe5DIapzGtGBQm71SlqGWjnIH6Vowt
|
||||
zmhAy/E3vV6F6tEMuxlWIyAfrVxCCAO1VZEEyYA4AApxNGwyJ+lVJRUsaKMw61SlFQzRAP/Z
|
||||
|
||||
X-ATTRIBUTE:Some String
|
||||
BDAY:19800101
|
||||
GEO:35.6563854,139.6994233
|
||||
URL:http://www.example.com/
|
||||
REV:20080424T195243Z
|
||||
END:VCARD
|
||||
@@ -0,0 +1,104 @@
|
||||
BEGIN:VCARD␍
|
||||
VERSION:3.0␍
|
||||
N:Smith;Bob;;;␍
|
||||
FN:Bob Smith␍
|
||||
ORG:Smith Auto Repair;␍
|
||||
item1.EMAIL;type=INTERNET;type=pref:bob@smithauto.com␍
|
||||
TEL;type=CELL;type=VOICE;type=pref:(650) 555-1212␍
|
||||
item2.URL;type=pref:www.smithauto.com␍
|
||||
item2.X-ABLabel:_$!<HomePage>!$_␍
|
||||
PHOTO;ENCODING=b;TYPE=JPEG:/9j/4AAQSkZJRgABAQAAAQABAAD/4gxYSUNDX1BST0ZJTEUA␍
|
||||
AQEAAAxITGlubwIQAABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1␍
|
||||
JHQgAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA␍
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAABFjcHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8A␍
|
||||
AAABRia3B0AAACBAAAABRyWFlaAAACGAAAABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5k␍
|
||||
AAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAADTAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAAB␍
|
||||
RtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJDAAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAE␍
|
||||
PAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQ␍
|
||||
AAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAABJzUkdCIElFQzYxOTY2␍
|
||||
LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWF␍
|
||||
laIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUA␍
|
||||
AAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z2Rlc2MAAAAAAAAAFk␍
|
||||
lFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAA␍
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAC␍
|
||||
5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAAAA␍
|
||||
AC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAA␍
|
||||
AAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9uIGlu␍
|
||||
IElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbi␍
|
||||
BJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAAABOk/gAUXy4A␍
|
||||
EM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAAAAABAAAAAA␍
|
||||
AAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZ␍
|
||||
AB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAK␍
|
||||
QAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgB␍
|
||||
PgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDA␍
|
||||
IUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMh␍
|
||||
Ay0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH␍
|
||||
4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYG␍
|
||||
JwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICw␍
|
||||
gfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpU␍
|
||||
CmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDP␍
|
||||
MNDQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P␍
|
||||
7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIx␍
|
||||
NDE2MTgxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbW␍
|
||||
FvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGu␍
|
||||
wbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4f␍
|
||||
aR+UH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHy␍
|
||||
RNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClr␍
|
||||
KZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLy␍
|
||||
QvWi+RL8cv/jA1MGwwpDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1␍
|
||||
TTWHNcI1/TY3NnI2rjbpNyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qj␍
|
||||
voPCc8ZTykPOM9Ij1hPaE94D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1␍
|
||||
QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSj␍
|
||||
dKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZS␍
|
||||
MVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVl␍
|
||||
qmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GND␍
|
||||
Y5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK␍
|
||||
9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52␍
|
||||
m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqI␍
|
||||
EKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuW␍
|
||||
i/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflw␍
|
||||
qXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopaj␍
|
||||
BqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1q+msXKzQrUStuK4trqGvFq␍
|
||||
+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7wh␍
|
||||
vJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZGxsPHQce/yD3IvMk6yb␍
|
||||
nKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnUy9VO1dHWVdbY11zX␍
|
||||
4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj4+vkc+T85YTmDe␍
|
||||
aW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozzGfOn9DT0wvVQ␍
|
||||
9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////4QBMRXhpZgAATU0AKgAAAA␍
|
||||
gAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAMqADAAQAAAABAAAA␍
|
||||
MgAAAAD/2wBDAAIBAQIBAQICAQICAgICAwUDAwMDAwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ␍
|
||||
0JCgsLDAwMBwkNDg0MDgsMDAv/2wBDAQICAgMCAwUDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsL␍
|
||||
CwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwv/wAARCAAyADIDASIAAhEBAxEB/8QAHw␍
|
||||
AAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR␍
|
||||
BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRk␍
|
||||
dISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKz␍
|
||||
tLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQ␍
|
||||
EBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJB␍
|
||||
UQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1␍
|
||||
RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3␍
|
||||
uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/K␍
|
||||
4L9oT9oLR/2efBo1PxGr3V3csYrGyjYCS6kAyeT91RwWbnGRwSQD1eqeMtI0PVbax1rVNOs769␍
|
||||
IFvbz3KRyz5OBsQnLcgjgV8u/tsfBi9+LXxcink8a+B9GtdPsUggstV1XyJ4ySXdzHsON2V5zy␍
|
||||
FFfHca53i8qyurUyqKniLqK1Xut9Wm7aLVJ7u2ljKtNxi+Xc8u+Inxa+K/gvwnpeqw3UvhPwx4␍
|
||||
qnm1HS7XTpk2xhyHZQeZFU7t4UkD5jgDoM34S/HL4weNvGVtonw88Vaxfanfq6xxXU6SJgKWYk␍
|
||||
zAhcAE56+nart7+y3qmpWFpa6l8U/hvcWtgCltDL4id47cNyRGpTCg98Ypuk/sq6joGoxXuhfF␍
|
||||
H4a2V5Ad0U9v4haKWM9PlZUBHUjj1r+Y54fiGWMp1YyrqkuW6VeKlZJc6i01GKvflXLaKsraHm␍
|
||||
2qXvrb1Po39jv9o2y15T8PfFGm2/h/xJ4eD2ywRybor3y2IkZSST5m4MzAk7slgTzj3+vgj4e/␍
|
||||
s36j4O+JOj67afEr4aSXljqEdySmvFpZjvG5clPmLgsvPXdX27rPxG8P+HdftdK1/W9JstTvsf␍
|
||||
Z7Se7SOabPA2oTk5PA9e1f0D4c55ja+Wyo5vFQdJqMW3H3ov4E+XTmVraJX00vc78PNuNpm1RR␍
|
||||
RX6YdB+cX7dF5NP+1B4oaaV2a3MCxEtzEBBGQF9MEk/U079tO5k1D4yWs967SzTaDp0ju3JZjD␍
|
||||
kk/U1D+3Ef+MnvF3+/D/6Tx0/9sf8A5K3Yf9i9pv8A6Ir+JeIpN1M8Tf8AzEx/9Krnjz+36/5n␍
|
||||
lG0ego2D0H5UtFfntjnLnhtAfEumcD/j8h7f9NFrv/2zLuWf9pzxi8sjs8V0io27lAsMe0A9sd␍
|
||||
q4Hw1/yMum/wDX3D/6MWu+/bR/5Oc8af8AXzH/AOk8VfRUdMgxH/X6l/6brmi/hv1X6n6PaDM1␍
|
||||
xoVlJMxZ3gRmJ6klRk0U3w3n/hHbD/r2j/8AQRRX960XenH0R7iPNfin+xn4J+L/AI/TxH4sgv␍
|
||||
1vSEFxHb3Hlw3oTgeauCc4AXKkZAr5O/4KDwJbftLXkcCKkcem2iqqjAUBCAAK/QiuH+LvwN8I␍
|
||||
/Eq3m1HxzoGn6lf2dq6wzyofMUAEgZBGQCSQDnGa/N+OuAKOe5dWpZbGFKrOcak5NW53FS3aTd␍
|
||||
/eb23v3bOetQU4tR0Z+YdFdz+zJ4YsPGvx68K6V4ptY73T767KTwSZ2yqI3bBxz1Ar03/goJ8I␍
|
||||
fDfwk8ReGIfhxpFtpMV7bXDzrCG/eFWjCkkk9AT+Z9a/lTC8MYjF5JiM9jOPsqU1BrXmbfLqtL␍
|
||||
W95de55apNwc+x4N4a/wCRl03P/P3D/wCjFr9GPiJ+yB4G+KXxCj8S+LtPnk1DKGdI7hkhvNgA␍
|
||||
XzUHXgAcYyAAc15l+wd8C/CHib4OaT4k8QaBYXuuQ307JdzKXZSknyHBOOMDHHGK+nK/ofws4C␍
|
||||
pUMqlXzOMKtPEezqRi1flspNN3Vr+9bS/XV3PQw1C0Ly1vqIqhVAUAAcADtRS0V+4nYFVtYUNp␍
|
||||
N0GAIMLgg9/lNFFZ1vgl6MD82/2POP2mvBX/AF+t/wCiZK9o/wCCpqKNd8FMANxgvATjkgNBj+␍
|
||||
Z/Oiiv5EyP/k3eZ/8AX6H50jyof7vL1/yPWf8AgnuAP2YNJI6m6u8+/wC/evbKKK/pbgf/AJJ7␍
|
||||
L/8ArzT/APSUejR/hx9Aooor6k0P/9k=␍
|
||||
END:VCARD␍
|
||||
@@ -0,0 +1,5 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
FN;CHARSET=SHIFT_JIS:ˆÉ”\ Œ\ˆê ˆÉ—\
|
||||
N;CHARSET=SHIFT_JIS:ˆÉ”\;Œ\ˆê;ˆÉ—\;;
|
||||
END:VCARD
|
||||
@@ -0,0 +1,5 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
N:F;G;M;;
|
||||
TEL;TYPE="费":1
|
||||
END:VCARD
|
||||
@@ -0,0 +1,5 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
N:F;G;M;;
|
||||
TEL;TYPE=PAGER,WORK,MSG:6101231234@pagersample.com
|
||||
END:VCARD
|
||||
@@ -0,0 +1,6 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
FN:Pause Wait
|
||||
N:Pause;Wait;;;
|
||||
TEL:p1234p5678w9
|
||||
END:VCARD
|
||||
@@ -0,0 +1,13 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
FN:And Roid
|
||||
N:And;Roid;;;
|
||||
ORG:Open;Handset; Alliance
|
||||
SORT-STRING:android
|
||||
TEL;TYPE=PREF;TYPE=VOICE:0300000000
|
||||
CLASS:PUBLIC
|
||||
X-GNO:0
|
||||
X-GN:group0
|
||||
X-REDUCTION:0
|
||||
REV:20081031T065854Z
|
||||
END:VCARD
|
||||
@@ -0,0 +1,5 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
FN:Android
|
||||
IMPP;TYPE=personal:sip:android@android.example.com
|
||||
END:VCARD
|
||||
@@ -0,0 +1,7 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
FN:安藤 ロイド
|
||||
N:安藤;ロイド;;;
|
||||
TEL;TYPE=HOME:tel:1
|
||||
TEL;TYPE=HOME:sip:example@example.com
|
||||
END:VCARD
|
||||
@@ -0,0 +1,6 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
FN:安藤 ロイド
|
||||
N;SORT-AS="あんどう;ろいど":安藤;ロイド;;;
|
||||
ORG;TYPE=WORK;SORT-AS="ぐーぐる;けんさくぶもん":グーグル;検索部門
|
||||
END:VCARD
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard;
|
||||
|
||||
import com.android.vcard.JapaneseUtils;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class JapaneseUtilsTest extends TestCase {
|
||||
static final char TEST_CONTAINED_CHAR = '\uFFE5';
|
||||
static final char TEST_UNCONTAINED_CHAR = '\uFFF5';
|
||||
|
||||
public void testTryGetHalfWidthText() {
|
||||
assertNull(JapaneseUtils.tryGetHalfWidthText(TEST_UNCONTAINED_CHAR));
|
||||
assertEquals(JapaneseUtils.tryGetHalfWidthText(TEST_CONTAINED_CHAR), "\u005C\u005C");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.provider.ContactsContract;
|
||||
|
||||
import com.android.vcard.VCardBuilder;
|
||||
import com.android.vcard.VCardConfig;
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Unit test for VCardBuilder.
|
||||
*/
|
||||
public class VCardBuilderTest extends TestCase {
|
||||
|
||||
public void testVCardNameFieldFromDisplayName() {
|
||||
final ArrayList<ContentValues> contentList = Lists.newArrayList();
|
||||
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "ने");
|
||||
contentList.add(values);
|
||||
|
||||
final VCardBuilder builder = new VCardBuilder(VCardConfig.VCARD_TYPE_DEFAULT);
|
||||
builder.appendNameProperties(contentList);
|
||||
final String actual = builder.toString();
|
||||
|
||||
final String expectedCommon = ";CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:" +
|
||||
"=E0=A4=A8=E0=A5=87";
|
||||
|
||||
final String expectedName = "N" + expectedCommon + ";;;;";
|
||||
final String expectedFullName = "FN" + expectedCommon;
|
||||
|
||||
assertTrue("Actual value:\n" + actual + " expected to contain\n" + expectedName +
|
||||
"\nbut does not.", actual.contains(expectedName));
|
||||
assertTrue("Actual value:\n" + actual + " expected to contain\n" + expectedFullName +
|
||||
"\nbut does not.", actual.contains(expectedFullName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.VCardConfig;
|
||||
import com.android.vcard.VCardConstants;
|
||||
import com.android.vcard.VCardEntry;
|
||||
import com.android.vcard.VCardEntry.AndroidCustomData;
|
||||
import com.android.vcard.VCardEntry.AnniversaryData;
|
||||
import com.android.vcard.VCardEntry.BirthdayData;
|
||||
import com.android.vcard.VCardEntry.EmailData;
|
||||
import com.android.vcard.VCardEntry.EntryElement;
|
||||
import com.android.vcard.VCardEntry.EntryLabel;
|
||||
import com.android.vcard.VCardEntry.ImData;
|
||||
import com.android.vcard.VCardEntry.NameData;
|
||||
import com.android.vcard.VCardEntry.NicknameData;
|
||||
import com.android.vcard.VCardEntry.NoteData;
|
||||
import com.android.vcard.VCardEntry.OrganizationData;
|
||||
import com.android.vcard.VCardEntry.PhoneData;
|
||||
import com.android.vcard.VCardEntry.PhotoData;
|
||||
import com.android.vcard.VCardEntry.PostalData;
|
||||
import com.android.vcard.VCardEntry.SipData;
|
||||
import com.android.vcard.VCardEntryConstructor;
|
||||
import com.android.vcard.VCardEntryHandler;
|
||||
import com.android.vcard.VCardInterpreter;
|
||||
import com.android.vcard.VCardProperty;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Im;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Organization;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
|
||||
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class VCardEntryTests extends AndroidTestCase {
|
||||
private class MockVCardEntryHandler implements VCardEntryHandler {
|
||||
private List<VCardEntry> mEntries = new ArrayList<VCardEntry>();
|
||||
private boolean mOnStartCalled;
|
||||
private boolean mOnEndCalled;
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
assertFalse(mOnStartCalled);
|
||||
mOnStartCalled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryCreated(VCardEntry entry) {
|
||||
assertTrue(mOnStartCalled);
|
||||
assertFalse(mOnEndCalled);
|
||||
mEntries.add(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd() {
|
||||
assertTrue(mOnStartCalled);
|
||||
assertFalse(mOnEndCalled);
|
||||
mOnEndCalled = true;
|
||||
}
|
||||
|
||||
public List<VCardEntry> getEntries() {
|
||||
return mEntries;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests VCardEntry and related clasess can handle nested classes given
|
||||
* {@link VCardInterpreter} is called appropriately.
|
||||
*
|
||||
* This test manually calls VCardInterpreter's callback mechanism and checks
|
||||
* {@link VCardEntryConstructor} constructs {@link VCardEntry} per given calls.
|
||||
*
|
||||
* Intended vCard is as follows:
|
||||
* <code>
|
||||
* BEGIN:VCARD
|
||||
* N:test1
|
||||
* BEGIN:VCARD
|
||||
* N:test2
|
||||
* END:VCARD
|
||||
* TEL:1
|
||||
* END:VCARD
|
||||
* </code>
|
||||
*/
|
||||
public void testNestHandling() {
|
||||
VCardEntryConstructor entryConstructor = new VCardEntryConstructor();
|
||||
MockVCardEntryHandler entryHandler = new MockVCardEntryHandler();
|
||||
entryConstructor.addEntryHandler(entryHandler);
|
||||
|
||||
entryConstructor.onVCardStarted();
|
||||
entryConstructor.onEntryStarted();
|
||||
VCardProperty property = new VCardProperty();
|
||||
property.setName(VCardConstants.PROPERTY_N);
|
||||
property.setValues("test1");
|
||||
entryConstructor.onPropertyCreated(property);
|
||||
|
||||
entryConstructor.onEntryStarted(); // begin nest
|
||||
property = new VCardProperty();
|
||||
property.setName(VCardConstants.PROPERTY_N);
|
||||
property.setValues("test2");
|
||||
entryConstructor.onPropertyCreated(property);
|
||||
entryConstructor.onEntryEnded(); // end nest
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName(VCardConstants.PROPERTY_TEL);
|
||||
property.setValues("1");
|
||||
entryConstructor.onPropertyCreated(property);
|
||||
entryConstructor.onEntryEnded();
|
||||
entryConstructor.onVCardEnded();
|
||||
|
||||
List<VCardEntry> entries = entryHandler.getEntries();
|
||||
assertEquals(2, entries.size());
|
||||
VCardEntry parent = entries.get(1);
|
||||
VCardEntry child = entries.get(0);
|
||||
assertEquals("test1", parent.getDisplayName());
|
||||
assertEquals("test2", child.getDisplayName());
|
||||
List<VCardEntry.PhoneData> phoneList = parent.getPhoneList();
|
||||
assertNotNull(phoneList);
|
||||
assertEquals(1, phoneList.size());
|
||||
assertEquals("1", phoneList.get(0).getNumber());
|
||||
}
|
||||
|
||||
private class MockEntryElementIterator implements VCardEntry.EntryElementIterator {
|
||||
private boolean mStartCalled;
|
||||
private boolean mEndCalled;
|
||||
private EntryLabel mLabel;
|
||||
private final Map<EntryLabel, EntryElement> mExpectedElements =
|
||||
new HashMap<EntryLabel, EntryElement>();
|
||||
|
||||
public void addExpectedElement(EntryElement elem) {
|
||||
mExpectedElements.put(elem.getEntryLabel(), elem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIterationStarted() {
|
||||
assertFalse(mStartCalled);
|
||||
assertFalse(mEndCalled);
|
||||
assertNull(mLabel);
|
||||
mStartCalled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIterationEnded() {
|
||||
assertTrue(mStartCalled);
|
||||
assertFalse(mEndCalled);
|
||||
assertNull(mLabel);
|
||||
assertTrue("Expected Elements remaining: " +
|
||||
Arrays.toString(mExpectedElements.values().toArray()),
|
||||
mExpectedElements.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onElementGroupStarted(EntryLabel label) {
|
||||
assertTrue(mStartCalled);
|
||||
assertFalse(mEndCalled);
|
||||
assertNull(mLabel);
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onElementGroupEnded() {
|
||||
assertTrue(mStartCalled);
|
||||
assertFalse(mEndCalled);
|
||||
assertNotNull(mLabel);
|
||||
mLabel = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onElement(EntryElement elem) {
|
||||
EntryElement expectedElem = mExpectedElements.remove(elem.getEntryLabel());
|
||||
assertNotNull("Unexpected elem: " + elem.toString(), expectedElem);
|
||||
assertEquals(expectedElem, elem);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests every element in VCardEntry is iterated by
|
||||
* {@link VCardEntry#iterateAllData(com.android.vcard.VCardEntry.EntryElementIterator)}.
|
||||
*/
|
||||
public void testEntryElementIterator() {
|
||||
VCardEntry entry = new VCardEntry();
|
||||
MockEntryElementIterator iterator = new MockEntryElementIterator();
|
||||
|
||||
VCardProperty property = new VCardProperty();
|
||||
property.setName("N");
|
||||
property.setValues("family", "given", "middle", "prefix", "suffix");
|
||||
entry.addProperty(property);
|
||||
NameData nameData = new NameData();
|
||||
nameData.setFamily("family");
|
||||
nameData.setGiven("given");
|
||||
nameData.setMiddle("middle");
|
||||
nameData.setPrefix("prefix");
|
||||
nameData.setSuffix("suffix");
|
||||
iterator.addExpectedElement(nameData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("TEL");
|
||||
property.setParameter("TYPE", "HOME");
|
||||
property.setValues("1");
|
||||
entry.addProperty(property);
|
||||
PhoneData phoneData = new PhoneData("1", Phone.TYPE_HOME, null, false);
|
||||
iterator.addExpectedElement(phoneData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("EMAIL");
|
||||
property.setParameter("TYPE", "WORK");
|
||||
property.setValues("email");
|
||||
entry.addProperty(property);
|
||||
EmailData emailData = new EmailData("email", Email.TYPE_WORK, null, false);
|
||||
iterator.addExpectedElement(emailData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("ADR");
|
||||
property.setParameter("TYPE", "HOME");
|
||||
property.setValues(null, null, "street");
|
||||
entry.addProperty(property);
|
||||
PostalData postalData = new PostalData(null, null, "street", null, null, null,
|
||||
null, StructuredPostal.TYPE_HOME, null, false,
|
||||
VCardConfig.VCARD_TYPE_DEFAULT);
|
||||
iterator.addExpectedElement(postalData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("ORG");
|
||||
property.setValues("organization", "depertment");
|
||||
entry.addProperty(property);
|
||||
OrganizationData organizationData = new OrganizationData(
|
||||
"organization", "depertment", null, null, Organization.TYPE_WORK, false);
|
||||
iterator.addExpectedElement(organizationData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("X-GOOGLE-TALK");
|
||||
property.setParameter("TYPE", "WORK");
|
||||
property.setValues("googletalk");
|
||||
entry.addProperty(property);
|
||||
ImData imData = new ImData(
|
||||
Im.PROTOCOL_GOOGLE_TALK, null, "googletalk", Im.TYPE_WORK, false);
|
||||
iterator.addExpectedElement(imData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("PHOTO");
|
||||
property.setParameter("TYPE", "PNG");
|
||||
byte[] photoBytes = new byte[] {1};
|
||||
property.setByteValue(photoBytes);
|
||||
entry.addProperty(property);
|
||||
PhotoData photoData = new PhotoData("PNG", photoBytes, false);
|
||||
iterator.addExpectedElement(photoData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("X-SIP");
|
||||
property.setValues("sipdata");
|
||||
entry.addProperty(property);
|
||||
SipData sipData = new SipData("sip:sipdata", SipAddress.TYPE_OTHER, null, false);
|
||||
iterator.addExpectedElement(sipData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("NICKNAME");
|
||||
property.setValues("nickname");
|
||||
entry.addProperty(property);
|
||||
NicknameData nicknameData = new NicknameData("nickname");
|
||||
iterator.addExpectedElement(nicknameData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("NOTE");
|
||||
property.setValues("note");
|
||||
entry.addProperty(property);
|
||||
NoteData noteData = new NoteData("note");
|
||||
iterator.addExpectedElement(noteData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("BDAY");
|
||||
property.setValues("birthday");
|
||||
entry.addProperty(property);
|
||||
BirthdayData birthdayData = new BirthdayData("birthday");
|
||||
iterator.addExpectedElement(birthdayData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("ANNIVERSARY");
|
||||
property.setValues("anniversary");
|
||||
entry.addProperty(property);
|
||||
AnniversaryData anniversaryData = new AnniversaryData("anniversary");
|
||||
iterator.addExpectedElement(anniversaryData);
|
||||
|
||||
property = new VCardProperty();
|
||||
property.setName("X-ANDROID-CUSTOM");
|
||||
property.setValues("mime;value");
|
||||
entry.addProperty(property);
|
||||
AndroidCustomData androidCustom = new AndroidCustomData("mime", Arrays.asList("value"));
|
||||
iterator.addExpectedElement(androidCustom);
|
||||
|
||||
entry.iterateAllData(iterator);
|
||||
}
|
||||
|
||||
public void testToString() {
|
||||
VCardEntry entry = new VCardEntry();
|
||||
VCardProperty property = new VCardProperty();
|
||||
property.setName("N");
|
||||
property.setValues("Family", "Given", "Middle", "Prefix", "Suffix");
|
||||
entry.addProperty(property);
|
||||
entry.consolidateFields();
|
||||
|
||||
String result = entry.toString();
|
||||
assertNotNull(result);
|
||||
|
||||
assertTrue(result.contains(String.valueOf(entry.hashCode())));
|
||||
assertTrue(result.contains(VCardEntry.EntryLabel.NAME.toString()));
|
||||
assertTrue(result.contains("Family"));
|
||||
assertTrue(result.contains("Given"));
|
||||
assertTrue(result.contains("Middle"));
|
||||
assertTrue(result.contains("Prefix"));
|
||||
assertTrue(result.contains("Suffix"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that VCardEntry emits correct insert operation for name field.
|
||||
*/
|
||||
public void testConstructInsertOperationsInsertName() {
|
||||
VCardEntry entry = new VCardEntry();
|
||||
VCardProperty property = new VCardProperty();
|
||||
property.setName("N");
|
||||
property.setValues("Family", "Given", "Middle", "Prefix", "Suffix");
|
||||
entry.addProperty(property);
|
||||
entry.consolidateFields();
|
||||
|
||||
NameData nameData = entry.getNameData();
|
||||
assertEquals("Family", nameData.getFamily());
|
||||
assertEquals("Given", nameData.getGiven());
|
||||
assertEquals("Middle", nameData.getMiddle());
|
||||
assertEquals("Prefix", nameData.getPrefix());
|
||||
assertEquals("Suffix", nameData.getSuffix());
|
||||
|
||||
ContentResolver resolver = getContext().getContentResolver();
|
||||
ArrayList<ContentProviderOperation> operationList =
|
||||
new ArrayList<ContentProviderOperation>();
|
||||
entry.constructInsertOperations(resolver, operationList);
|
||||
|
||||
// Need too many details for testing these. Just check basics.
|
||||
// TODO: introduce nice-to-test mechanism here.
|
||||
assertEquals(2, operationList.size());
|
||||
assertEquals(ContentProviderOperation.TYPE_INSERT, operationList.get(0).getType());
|
||||
assertEquals(ContentProviderOperation.TYPE_INSERT, operationList.get(1).getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that VCardEntry refrains from emitting unnecessary insert operation.
|
||||
*/
|
||||
public void testConstructInsertOperationsEmptyData() {
|
||||
VCardEntry entry = new VCardEntry();
|
||||
ContentResolver resolver = getContext().getContentResolver();
|
||||
ArrayList<ContentProviderOperation> operationList =
|
||||
new ArrayList<ContentProviderOperation>();
|
||||
entry.constructInsertOperations(resolver, operationList);
|
||||
assertEquals(0, operationList.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that VCardEntry can add an account via the constructor
|
||||
*/
|
||||
public void testConstructor_withAccount_canGetAccount() {
|
||||
Account account = new Account("test-type", "test-name");
|
||||
VCardEntry entry = new VCardEntry(VCardConfig.VCARD_TYPE_V21_GENERIC, account);
|
||||
assertEquals(entry.getAccount(), account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that VCardEntry can add a null account via the constructor
|
||||
*/
|
||||
public void testConstructor_withNullAccount_canGetNullAccount() {
|
||||
VCardEntry entry = new VCardEntry(VCardConfig.VCARD_TYPE_V21_GENERIC, null);
|
||||
assertEquals(entry.getAccount(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that VCardEntry can add an account via the setter, updating a null account to a value
|
||||
*/
|
||||
public void testSetAccount_fromNullToValue_canGetAccount() {
|
||||
Account account = new Account("test-type", "test-name");
|
||||
VCardEntry entry = new VCardEntry();
|
||||
assertEquals(entry.getAccount(), null);
|
||||
entry.setAccount(account);
|
||||
assertEquals(entry.getAccount(), account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that VCardEntry can add an account via the setter, changing one account to another
|
||||
*/
|
||||
public void testSetAccount_fromToNewValue_canGetAccount() {
|
||||
Account account1 = new Account("test-type-1", "test-name-1");
|
||||
VCardEntry entry = new VCardEntry(VCardConfig.VCARD_TYPE_V21_GENERIC, account1);
|
||||
assertEquals(entry.getAccount(), account1);
|
||||
|
||||
Account account2 = new Account("test-type-2", "test-name-2");
|
||||
entry.setAccount(account2);
|
||||
assertEquals(entry.getAccount(), account2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that VCardEntry can add an account via the setter, changing one account to another
|
||||
*/
|
||||
public void testSetAccount_setValueTwice_canGetAccount() {
|
||||
VCardEntry entry = new VCardEntry();
|
||||
assertEquals(entry.getAccount(), null);
|
||||
|
||||
Account account1 = new Account("test-type-1", "test-name-1");
|
||||
entry.setAccount(account1);
|
||||
assertEquals(entry.getAccount(), account1);
|
||||
|
||||
Account account2 = new Account("test-type-2", "test-name-2");
|
||||
entry.setAccount(account2);
|
||||
assertEquals(entry.getAccount(), account2);
|
||||
}
|
||||
|
||||
// TODO: add bunch of test for constructInsertOperations..
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.tests.testutils.VCardTestsBase;
|
||||
|
||||
/**
|
||||
* Test cases specific for nested vCard.
|
||||
*/
|
||||
public class VCardImporterNestTests extends VCardTestsBase {
|
||||
public void testSimpleNest() {
|
||||
mVerifier.initForImportTest(V21, R.raw.v21_nest);
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNodeWithOrder("N", "nest1");
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNodeWithOrder("N", "nest2");
|
||||
// Parent comes last.
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNodeWithOrder("N", "parent")
|
||||
.addExpectedNodeWithOrder("TEL", "1");
|
||||
}
|
||||
|
||||
public void testSimpleNestWithMime() {
|
||||
mVerifier.initForImportTest(V21, R.raw.v21_nest_with_mime);
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNodeWithOrder("N", "nest1");
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNodeWithOrder("N", "nest2");
|
||||
// Parent comes last.
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNodeWithOrder("N", "parent")
|
||||
.addExpectedNodeWithOrder("TEL", "1");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Nickname;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Note;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
|
||||
|
||||
import com.android.vcard.VCardConfig;
|
||||
import com.android.vcard.VCardConstants;
|
||||
import com.android.vcard.tests.testutils.ContactEntry;
|
||||
import com.android.vcard.tests.testutils.ContentValuesBuilder;
|
||||
import com.android.vcard.tests.testutils.PropertyNodesVerifierElem;
|
||||
import com.android.vcard.tests.testutils.VCardTestsBase;
|
||||
import com.android.vcard.tests.testutils.PropertyNodesVerifierElem.TypeSet;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class VCardJapanizationTests extends VCardTestsBase {
|
||||
private void testNameUtf8Common(int vcardType) {
|
||||
mVerifier.initForExportTest(vcardType);
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
|
||||
.put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
|
||||
.put(StructuredName.MIDDLE_NAME, "B")
|
||||
.put(StructuredName.PREFIX, "Dr.")
|
||||
.put(StructuredName.SUFFIX, "Ph.D");
|
||||
ContentValues contentValues =
|
||||
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndUtf8 : null);
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNode("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
|
||||
contentValues)
|
||||
.addExpectedNode("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
|
||||
Arrays.asList(
|
||||
"\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
|
||||
null, contentValues, null, null);
|
||||
}
|
||||
|
||||
public void testNameUtf8V21() {
|
||||
testNameUtf8Common(VCardConfig.VCARD_TYPE_V21_JAPANESE);
|
||||
}
|
||||
|
||||
public void testNameUtf8V30() {
|
||||
testNameUtf8Common(VCardConfig.VCARD_TYPE_V30_JAPANESE);
|
||||
}
|
||||
|
||||
public void testNameShiftJis() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V30_JAPANESE, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
|
||||
.put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
|
||||
.put(StructuredName.MIDDLE_NAME, "B")
|
||||
.put(StructuredName.PREFIX, "Dr.")
|
||||
.put(StructuredName.SUFFIX, "Ph.D");
|
||||
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNode("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
|
||||
mContentValuesForSJis)
|
||||
.addExpectedNode("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
|
||||
Arrays.asList(
|
||||
"\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
|
||||
null, mContentValuesForSJis, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* DoCoMo phones require all name elements should be in "family name" field.
|
||||
*/
|
||||
public void testNameDoCoMo() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
|
||||
.put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
|
||||
.put(StructuredName.MIDDLE_NAME, "B")
|
||||
.put(StructuredName.PREFIX, "Dr.")
|
||||
.put(StructuredName.SUFFIX, "Ph.D");
|
||||
|
||||
final String fullName = "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D";
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNode("N", fullName + ";;;;",
|
||||
Arrays.asList(fullName, "", "", "", ""),
|
||||
null, mContentValuesForSJis, null, null)
|
||||
.addExpectedNode("FN", fullName, mContentValuesForSJis)
|
||||
.addExpectedNode("SOUND", ";;;;", new TypeSet("X-IRMC-N"))
|
||||
.addExpectedNode("TEL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("ADR", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("X-CLASS", "PUBLIC")
|
||||
.addExpectedNode("X-REDUCTION", "")
|
||||
.addExpectedNode("X-NO", "")
|
||||
.addExpectedNode("X-DCM-HMN-MODE", "");
|
||||
}
|
||||
|
||||
private void testPhoneticNameCommon(int vcardType, String charset) {
|
||||
mVerifier.initForExportTest(vcardType, charset);
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
|
||||
.put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
|
||||
.put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
|
||||
|
||||
final ContentValues contentValues =
|
||||
("SHIFT_JIS".equalsIgnoreCase(charset) ?
|
||||
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndSJis :
|
||||
mContentValuesForSJis) :
|
||||
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndUtf8 : null));
|
||||
PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
|
||||
elem.addExpectedNode("X-PHONETIC-LAST-NAME", "\u3084\u307E\u3060",
|
||||
contentValues)
|
||||
.addExpectedNode("X-PHONETIC-MIDDLE-NAME",
|
||||
"\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0",
|
||||
contentValues)
|
||||
.addExpectedNode("X-PHONETIC-FIRST-NAME", "\u305F\u308D\u3046",
|
||||
contentValues);
|
||||
if (!VCardConfig.isVersion21(vcardType)) {
|
||||
elem.addExpectedNode("SORT-STRING",
|
||||
"\u3084\u307E\u3060 \u30DF\u30C9\u30EB\u30CD\u30FC\u30E0 \u305F\u308D\u3046",
|
||||
contentValues);
|
||||
}
|
||||
ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
|
||||
.addExpected(StructuredName.CONTENT_ITEM_TYPE);
|
||||
builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
|
||||
.put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
|
||||
.put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046")
|
||||
.put(StructuredName.DISPLAY_NAME,
|
||||
"\u3084\u307E\u3060 \u30DF\u30C9\u30EB\u30CD\u30FC\u30E0 " +
|
||||
"\u305F\u308D\u3046");
|
||||
}
|
||||
|
||||
public void testPhoneticNameForJapaneseV21Utf8() {
|
||||
testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, null);
|
||||
}
|
||||
|
||||
public void testPhoneticNameForJapaneseV21Sjis() {
|
||||
testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, "Shift_JIS");
|
||||
}
|
||||
|
||||
public void testPhoneticNameForJapaneseV30Utf8() {
|
||||
testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE, null);
|
||||
}
|
||||
|
||||
public void testPhoneticNameForJapaneseV30SJis() {
|
||||
testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE, "Shift_JIS");
|
||||
}
|
||||
|
||||
public void testPhoneticNameForMobileV21_1() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
|
||||
.put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
|
||||
.put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
|
||||
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNode("SOUND",
|
||||
"\uFF94\uFF8F\uFF80\uFF9E \uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91 " +
|
||||
"\uFF80\uFF9B\uFF73;;;;",
|
||||
mContentValuesForSJis, new TypeSet("X-IRMC-N"));
|
||||
ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
|
||||
.addExpected(StructuredName.CONTENT_ITEM_TYPE);
|
||||
builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF94\uFF8F\uFF80\uFF9E")
|
||||
.put(StructuredName.PHONETIC_MIDDLE_NAME,
|
||||
"\uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91")
|
||||
.put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF80\uFF9B\uFF73")
|
||||
.put(StructuredName.DISPLAY_NAME,
|
||||
"\uFF94\uFF8F\uFF80\uFF9E \uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91 " +
|
||||
"\uFF80\uFF9B\uFF73");
|
||||
}
|
||||
|
||||
public void testPhoneticNameForMobileV21_2() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
|
||||
.put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
|
||||
|
||||
mVerifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNode("SOUND", "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73;;;;",
|
||||
mContentValuesForSJis, new TypeSet("X-IRMC-N"));
|
||||
ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
|
||||
.addExpected(StructuredName.CONTENT_ITEM_TYPE);
|
||||
builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF94\uFF8F\uFF80\uFF9E")
|
||||
.put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF80\uFF9B\uFF73")
|
||||
.put(StructuredName.DISPLAY_NAME, "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73");
|
||||
}
|
||||
|
||||
private void testPostalAddressWithJapaneseCommon(int vcardType, String charset) {
|
||||
mVerifier.initForExportTest(vcardType, charset);
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107")
|
||||
.put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751")
|
||||
.put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02")
|
||||
.put(StructuredPostal.REGION, "\u00D7\u00D7\u770C")
|
||||
.put(StructuredPostal.POSTCODE, "494-1313")
|
||||
.put(StructuredPostal.COUNTRY, "\u65E5\u672C")
|
||||
.put(StructuredPostal.FORMATTED_ADDRESS,
|
||||
"\u3053\u3093\u306A\u3068\u3053\u308D\u3092\u898B"
|
||||
+ "\u308B\u306A\u3093\u3066\u6687\u4EBA\u3067\u3059\u304B\uFF1F")
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
|
||||
.put(StructuredPostal.LABEL, "\u304A\u3082\u3061\u304B\u3048\u308A");
|
||||
|
||||
ContentValues contentValues = ("UTF-8".equalsIgnoreCase(charset) ?
|
||||
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndSJis :
|
||||
mContentValuesForSJis) :
|
||||
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndUtf8 :
|
||||
mContentValuesForUtf8));
|
||||
|
||||
PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
|
||||
// LABEL must be ignored in vCard 2.1. As for vCard 3.0, the current behavior is
|
||||
// same as that in vCard 3.0, which can be changed in the future.
|
||||
elem.addExpectedNode("ADR", Arrays.asList("\u79C1\u66F8\u7BB107",
|
||||
"", "\u96DB\u898B\u6CA2\u6751", "\u9E7F\u9AA8\u5E02", "\u00D7\u00D7\u770C",
|
||||
"494-1313", "\u65E5\u672C"),
|
||||
contentValues);
|
||||
mVerifier.addContentValuesVerifierElem().addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107")
|
||||
.put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751")
|
||||
.put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02")
|
||||
.put(StructuredPostal.REGION, "\u00D7\u00D7\u770C")
|
||||
.put(StructuredPostal.POSTCODE, "494-1313")
|
||||
.put(StructuredPostal.COUNTRY, "\u65E5\u672C")
|
||||
.put(StructuredPostal.FORMATTED_ADDRESS,
|
||||
"\u65E5\u672C 494-1313 \u00D7\u00D7\u770C \u9E7F\u9AA8\u5E02 " +
|
||||
"\u96DB\u898B\u6CA2\u6751 " + "\u79C1\u66F8\u7BB107")
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME);
|
||||
}
|
||||
public void testPostalAddresswithJapaneseV21() {
|
||||
testPostalAddressWithJapaneseCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, "Shift_JIS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that only one address field is emitted toward DoCoMo phones.
|
||||
* Prefered type must (should?) be: HOME > WORK > OTHER > CUSTOM
|
||||
*/
|
||||
public void testPostalAdrressForDoCoMo_1() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
|
||||
.put(StructuredPostal.POBOX, "1");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
|
||||
.put(StructuredPostal.POBOX, "2");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
|
||||
.put(StructuredPostal.POBOX, "3");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
|
||||
.put(StructuredPostal.LABEL, "custom")
|
||||
.put(StructuredPostal.POBOX, "4");
|
||||
|
||||
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
|
||||
.addExpectedNode("TEL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("X-CLASS", "PUBLIC")
|
||||
.addExpectedNode("X-REDUCTION", "")
|
||||
.addExpectedNode("X-NO", "")
|
||||
.addExpectedNode("X-DCM-HMN-MODE", "")
|
||||
.addExpectedNode("ADR",
|
||||
Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
|
||||
}
|
||||
|
||||
public void testPostalAdrressForDoCoMo_2() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
|
||||
.put(StructuredPostal.POBOX, "1");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
|
||||
.put(StructuredPostal.POBOX, "2");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
|
||||
.put(StructuredPostal.LABEL, "custom")
|
||||
.put(StructuredPostal.POBOX, "3");
|
||||
|
||||
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
|
||||
.addExpectedNode("TEL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("X-CLASS", "PUBLIC")
|
||||
.addExpectedNode("X-REDUCTION", "")
|
||||
.addExpectedNode("X-NO", "")
|
||||
.addExpectedNode("X-DCM-HMN-MODE", "")
|
||||
.addExpectedNode("ADR",
|
||||
Arrays.asList("2", "", "", "", "", "", ""), new TypeSet("WORK"));
|
||||
}
|
||||
|
||||
public void testPostalAdrressForDoCoMo_3() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
|
||||
.put(StructuredPostal.LABEL, "custom1")
|
||||
.put(StructuredPostal.POBOX, "1");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
|
||||
.put(StructuredPostal.POBOX, "2");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
|
||||
.put(StructuredPostal.LABEL, "custom2")
|
||||
.put(StructuredPostal.POBOX, "3");
|
||||
|
||||
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
|
||||
.addExpectedNode("TEL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("X-CLASS", "PUBLIC")
|
||||
.addExpectedNode("X-REDUCTION", "")
|
||||
.addExpectedNode("X-NO", "")
|
||||
.addExpectedNode("X-DCM-HMN-MODE", "")
|
||||
.addExpectedNode("ADR",
|
||||
Arrays.asList("2", "", "", "", "", "", ""),
|
||||
new TypeSet("X-" + VCardConstants.PARAM_ADR_EXTRA_TYPE_OTHER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the vCard exporter tolerates null TYPE.
|
||||
*/
|
||||
public void testPostalAdrressForDoCoMo_4() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.POBOX, "1");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
|
||||
.put(StructuredPostal.POBOX, "2");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
|
||||
.put(StructuredPostal.POBOX, "3");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
|
||||
.put(StructuredPostal.POBOX, "4");
|
||||
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredPostal.POBOX, "5");
|
||||
|
||||
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
|
||||
.addExpectedNode("TEL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("X-CLASS", "PUBLIC")
|
||||
.addExpectedNode("X-REDUCTION", "")
|
||||
.addExpectedNode("X-NO", "")
|
||||
.addExpectedNode("X-DCM-HMN-MODE", "")
|
||||
.addExpectedNode("ADR",
|
||||
Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
|
||||
}
|
||||
|
||||
private void testJapanesePhoneNumberCommon(int vcardType) {
|
||||
mVerifier.initForExportTest(vcardType);
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
|
||||
.put(Phone.NUMBER, "0312341234")
|
||||
.put(Phone.TYPE, Phone.TYPE_HOME);
|
||||
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
|
||||
.put(Phone.NUMBER, "09012341234")
|
||||
.put(Phone.TYPE, Phone.TYPE_MOBILE);
|
||||
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
|
||||
.addExpectedNode("TEL", "03-1234-1234", new TypeSet("HOME"))
|
||||
.addExpectedNode("TEL", "090-1234-1234", new TypeSet("CELL"));
|
||||
}
|
||||
|
||||
public void testJapanesePhoneNumberV21_1() {
|
||||
testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE);
|
||||
}
|
||||
|
||||
public void testJapanesePhoneNumberV30() {
|
||||
testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE);
|
||||
}
|
||||
|
||||
public void testJapanesePhoneNumberDoCoMo() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
|
||||
.put(Phone.NUMBER, "0312341234")
|
||||
.put(Phone.TYPE, Phone.TYPE_HOME);
|
||||
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
|
||||
.put(Phone.NUMBER, "09012341234")
|
||||
.put(Phone.TYPE, Phone.TYPE_MOBILE);
|
||||
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
|
||||
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("X-CLASS", "PUBLIC")
|
||||
.addExpectedNode("X-REDUCTION", "")
|
||||
.addExpectedNode("X-NO", "")
|
||||
.addExpectedNode("X-DCM-HMN-MODE", "")
|
||||
.addExpectedNode("ADR", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("TEL", "03-1234-1234", new TypeSet("HOME"))
|
||||
.addExpectedNode("TEL", "090-1234-1234", new TypeSet("CELL"));
|
||||
}
|
||||
|
||||
public void testNoteDoCoMo() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
|
||||
ContactEntry entry = mVerifier.addInputEntry();
|
||||
entry.addContentValues(Note.CONTENT_ITEM_TYPE)
|
||||
.put(Note.NOTE, "note1");
|
||||
entry.addContentValues(Note.CONTENT_ITEM_TYPE)
|
||||
.put(Note.NOTE, "note2");
|
||||
entry.addContentValues(Note.CONTENT_ITEM_TYPE)
|
||||
.put(Note.NOTE, "note3");
|
||||
|
||||
// More than one note fields must be aggregated into one note.
|
||||
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
|
||||
.addExpectedNode("TEL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("X-CLASS", "PUBLIC")
|
||||
.addExpectedNode("X-REDUCTION", "")
|
||||
.addExpectedNode("X-NO", "")
|
||||
.addExpectedNode("X-DCM-HMN-MODE", "")
|
||||
.addExpectedNode("ADR", "", new TypeSet("HOME"))
|
||||
.addExpectedNode("NOTE", "note1\nnote2\nnote3", mContentValuesForQP);
|
||||
}
|
||||
|
||||
public void testAndroidCustomV21() {
|
||||
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_GENERIC);
|
||||
mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
|
||||
.put(Nickname.NAME, "\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC");
|
||||
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
|
||||
.addExpectedNode("X-ANDROID-CUSTOM",
|
||||
Arrays.asList(Nickname.CONTENT_ITEM_TYPE,
|
||||
"\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC",
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", ""),
|
||||
mContentValuesForQPAndUtf8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.VCardInterpreter;
|
||||
import com.android.vcard.VCardParser;
|
||||
import com.android.vcard.VCardParser_V21;
|
||||
import com.android.vcard.VCardParser_V30;
|
||||
import com.android.vcard.VCardProperty;
|
||||
import com.android.vcard.exception.VCardException;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests for basic {@link VCardParser} capability (e.g. if it calls callbacks
|
||||
* in {@link VCardInterpreter}}.
|
||||
*/
|
||||
public class VCardParserTests extends AndroidTestCase {
|
||||
private enum Order {
|
||||
START,
|
||||
END,
|
||||
START_ENTRY,
|
||||
END_ENTRY,
|
||||
PROPERTY_CREATED,
|
||||
}
|
||||
|
||||
private class MockVCardInterpreter implements VCardInterpreter {
|
||||
private final List<Order> mHistory = new ArrayList<Order>();
|
||||
private final List<Order> mExpectedOrder = new ArrayList<Order>();
|
||||
|
||||
public MockVCardInterpreter addExpectedOrder(Order order) {
|
||||
mExpectedOrder.add(order);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void inspectOrder(Order order) {
|
||||
mHistory.add(order);
|
||||
final Order top = mExpectedOrder.get(0);
|
||||
assertEquals(top, order);
|
||||
mExpectedOrder.remove(0);
|
||||
}
|
||||
|
||||
public void verify() {
|
||||
assertTrue(String.format("Remaining: " + Arrays.toString(mExpectedOrder.toArray())),
|
||||
mExpectedOrder.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVCardStarted() {
|
||||
inspectOrder(Order.START);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVCardEnded() {
|
||||
inspectOrder(Order.END);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryStarted() {
|
||||
inspectOrder(Order.START_ENTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryEnded() {
|
||||
inspectOrder(Order.END_ENTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyCreated(VCardProperty property) {
|
||||
inspectOrder(Order.PROPERTY_CREATED);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSimple() throws IOException, VCardException {
|
||||
InputStream inputStream = getContext().getResources().openRawResource(R.raw.v21_simple_1);
|
||||
try {
|
||||
VCardParser parser = new VCardParser_V21();
|
||||
MockVCardInterpreter interpreter = new MockVCardInterpreter();
|
||||
interpreter.addExpectedOrder(Order.START)
|
||||
.addExpectedOrder(Order.START_ENTRY)
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED)
|
||||
.addExpectedOrder(Order.END_ENTRY)
|
||||
.addExpectedOrder(Order.END);
|
||||
parser.addInterpreter(interpreter);
|
||||
parser.parse(inputStream);
|
||||
interpreter.verify();
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testNest() throws IOException, VCardException {
|
||||
InputStream inputStream = getContext().getResources().openRawResource(R.raw.v21_nest);
|
||||
try {
|
||||
VCardParser parser = new VCardParser_V21();
|
||||
MockVCardInterpreter interpreter = new MockVCardInterpreter();
|
||||
interpreter.addExpectedOrder(Order.START)
|
||||
.addExpectedOrder(Order.START_ENTRY)
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
|
||||
.addExpectedOrder(Order.START_ENTRY) // First nested vCard begins
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
|
||||
.addExpectedOrder(Order.END_ENTRY) // First nested vCard ends
|
||||
.addExpectedOrder(Order.START_ENTRY) // Second nested vCard begins
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
|
||||
.addExpectedOrder(Order.END_ENTRY) // Second nested vCard ends
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.END_ENTRY)
|
||||
.addExpectedOrder(Order.END);
|
||||
parser.addInterpreter(interpreter);
|
||||
parser.parse(inputStream);
|
||||
interpreter.verify();
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test vCard containing v3.0 line continuations and with non-standard
|
||||
* line terminators \r\r\n coming from iOS 6.1.3. Tests to make sure the
|
||||
* parser correctly skips the extra line terminators and still
|
||||
* successfully concatenates the multi-line block.
|
||||
*/
|
||||
public void testIosMultiline() throws IOException, VCardException {
|
||||
InputStream inputStream = getContext().getResources().openRawResource(R.raw.v30_ios_613_multiline);
|
||||
try {
|
||||
VCardParser parser = new VCardParser_V30();
|
||||
MockVCardInterpreter interpreter = new MockVCardInterpreter();
|
||||
interpreter.addExpectedOrder(Order.START)
|
||||
.addExpectedOrder(Order.START_ENTRY)
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For FN
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For ORG
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For item1
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For item2
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For item3
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For PHOTO
|
||||
.addExpectedOrder(Order.END_ENTRY)
|
||||
.addExpectedOrder(Order.END);
|
||||
parser.addInterpreter(interpreter);
|
||||
parser.parse(inputStream);
|
||||
interpreter.verify();
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if {@link VCardParser#parse(InputStream)} parses the whole vCard file and
|
||||
* {@link VCardParser#parseOne(InputStream)} parses just first entry of a vCard file
|
||||
* with multiple vCard entries.
|
||||
*/
|
||||
public void testParseOne() throws IOException, VCardException {
|
||||
InputStream inputStream =
|
||||
getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
|
||||
try {
|
||||
VCardParser parser = new VCardParser_V21();
|
||||
MockVCardInterpreter interpreter = new MockVCardInterpreter();
|
||||
interpreter.addExpectedOrder(Order.START)
|
||||
.addExpectedOrder(Order.START_ENTRY)
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For SOUND
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.END_ENTRY)
|
||||
.addExpectedOrder(Order.START_ENTRY)
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For SOUND
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.END_ENTRY)
|
||||
.addExpectedOrder(Order.START_ENTRY)
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For SOUND
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.END_ENTRY)
|
||||
.addExpectedOrder(Order.END);
|
||||
parser.addInterpreter(interpreter);
|
||||
// Use parse() to check we
|
||||
parser.parse(inputStream);
|
||||
interpreter.verify();
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
|
||||
inputStream = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
|
||||
try {
|
||||
VCardParser parser = new VCardParser_V21();
|
||||
MockVCardInterpreter interpreter = new MockVCardInterpreter();
|
||||
interpreter.addExpectedOrder(Order.START)
|
||||
.addExpectedOrder(Order.START_ENTRY)
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For SOUND
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
|
||||
.addExpectedOrder(Order.END_ENTRY)
|
||||
.addExpectedOrder(Order.END);
|
||||
parser.addInterpreter(interpreter);
|
||||
parser.parseOne(inputStream);
|
||||
interpreter.verify();
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import com.android.vcard.VCardConfig;
|
||||
import com.android.vcard.tests.testutils.VCardVerifier;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Tests confirming utilities for vCard tests work fine.
|
||||
*
|
||||
* Now that the foundation classes for vCard test cases became too complicated to
|
||||
* rely on without testing itself.
|
||||
*/
|
||||
public class VCardTestUtilsTests extends AndroidTestCase {
|
||||
public void testShouldFailAtPropertyNodeVerification() {
|
||||
boolean failureDetected = false;
|
||||
try {
|
||||
final VCardVerifier verifier = new VCardVerifier(this);
|
||||
verifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_GENERIC, R.raw.v21_backslash);
|
||||
verifier.addPropertyNodesVerifierElem()
|
||||
.addExpectedNodeWithOrder("N", ";A;B\\;C\\;;D;:E;\\\\;--", // wrong
|
||||
Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""))
|
||||
.addExpectedNodeWithOrder("FN", "A;B\\C\\;D:E\\\\");
|
||||
verifier.verify();
|
||||
} catch (AssertionFailedError e) {
|
||||
failureDetected = true;
|
||||
}
|
||||
if (!failureDetected) {
|
||||
TestCase.fail("Test case that should fail actually succeeded.");
|
||||
}
|
||||
}
|
||||
|
||||
public void testShouldFailAtContentValueVerification() {
|
||||
boolean failureDetected = false;
|
||||
try {
|
||||
final VCardVerifier verifier = new VCardVerifier(this);
|
||||
verifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_GENERIC, R.raw.v21_backslash);
|
||||
verifier.addContentValuesVerifierElem()
|
||||
.addExpected(StructuredName.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredName.GIVEN_NAME, "A;B\\")
|
||||
.put(StructuredName.MIDDLE_NAME, "C\\;")
|
||||
.put(StructuredName.PREFIX, "D")
|
||||
.put(StructuredName.SUFFIX, ":E");
|
||||
// DISPLAY_NAME is missing.
|
||||
verifier.verify();
|
||||
} catch (AssertionFailedError e) {
|
||||
failureDetected = true;
|
||||
}
|
||||
if (!failureDetected) {
|
||||
TestCase.fail("Test case that should fail actually succeeded.");
|
||||
}
|
||||
}
|
||||
|
||||
public void testShouldFailAtLineVerification() {
|
||||
boolean failureDetected = false;
|
||||
try {
|
||||
final VCardVerifier verifier = new VCardVerifier(this);
|
||||
verifier.initForExportTest(VCardConfig.VCARD_TYPE_V30_GENERIC);
|
||||
verifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
|
||||
.put(StructuredName.FAMILY_NAME, "\\")
|
||||
.put(StructuredName.GIVEN_NAME, ";")
|
||||
.put(StructuredName.MIDDLE_NAME, ",")
|
||||
.put(StructuredName.PREFIX, "\n")
|
||||
.put(StructuredName.DISPLAY_NAME, "[<{Unescaped:Asciis}>]");
|
||||
verifier.addLineVerifierElem()
|
||||
.addExpected("TEL:1") // wrong
|
||||
.addExpected("FN:[<{Unescaped:Asciis}>]");
|
||||
verifier.verify();
|
||||
} catch (AssertionFailedError e) {
|
||||
failureDetected = true;
|
||||
}
|
||||
if (!failureDetected) {
|
||||
TestCase.fail("Test case that should fail actually succeeded.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.vcard.VCardUtils;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class VCardUtilsTests extends TestCase {
|
||||
public void testContainsOnlyPrintableAscii() {
|
||||
assertTrue(VCardUtils.containsOnlyPrintableAscii((String)null));
|
||||
assertTrue(VCardUtils.containsOnlyPrintableAscii((String[])null));
|
||||
assertTrue(VCardUtils.containsOnlyPrintableAscii((List<String>)null));
|
||||
assertTrue(VCardUtils.containsOnlyPrintableAscii(""));
|
||||
assertTrue(VCardUtils.containsOnlyPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
|
||||
assertTrue(VCardUtils.containsOnlyPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0x20; i < 0x7F; i++) {
|
||||
builder.append((char)i);
|
||||
}
|
||||
assertTrue(VCardUtils.containsOnlyPrintableAscii(builder.toString()));
|
||||
assertTrue(VCardUtils.containsOnlyPrintableAscii("\r\n"));
|
||||
assertFalse(VCardUtils.containsOnlyPrintableAscii("\u0019"));
|
||||
assertFalse(VCardUtils.containsOnlyPrintableAscii("\u007F"));
|
||||
}
|
||||
|
||||
public void testContainsOnlyNonCrLfPrintableAscii() {
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String)null));
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String[])null));
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((List<String>)null));
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(""));
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0x20; i < 0x7F; i++) {
|
||||
builder.append((char)i);
|
||||
}
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(builder.toString()));
|
||||
assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u0019"));
|
||||
assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u007F"));
|
||||
assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\r"));
|
||||
assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\n"));
|
||||
}
|
||||
|
||||
public void testContainsOnlyAlphaDigitHyphen() {
|
||||
assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String)null));
|
||||
assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String[])null));
|
||||
assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((List<String>)null));
|
||||
assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen(""));
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
|
||||
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("0123456789-"));
|
||||
for (int i = 0; i < 0x30; i++) {
|
||||
if (i == 0x2D) { // -
|
||||
continue;
|
||||
}
|
||||
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
|
||||
}
|
||||
for (int i = 0x3A; i < 0x41; i++) {
|
||||
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
|
||||
}
|
||||
for (int i = 0x5B; i < 0x61; i++) {
|
||||
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
|
||||
}
|
||||
for (int i = 0x7B; i < 0x100; i++) {
|
||||
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
|
||||
}
|
||||
}
|
||||
|
||||
public void testToStringAvailableAsV30ParamValue() {
|
||||
// Smoke tests.
|
||||
assertEquals("HOME", VCardUtils.toStringAsV30ParamValue("HOME"));
|
||||
assertEquals("TEL", VCardUtils.toStringAsV30ParamValue("TEL"));
|
||||
assertEquals("PAGER", VCardUtils.toStringAsV30ParamValue("PAGER"));
|
||||
|
||||
assertTrue(TextUtils.isEmpty(VCardUtils.toStringAsV30ParamValue("")));
|
||||
assertTrue(TextUtils.isEmpty(VCardUtils.toStringAsV30ParamValue(null)));
|
||||
assertTrue(TextUtils.isEmpty(VCardUtils.toStringAsV30ParamValue(" \t")));
|
||||
|
||||
// non-Ascii must be allowed
|
||||
assertEquals("\u4E8B\u52D9\u6240",
|
||||
VCardUtils.toStringAsV30ParamValue("\u4E8B\u52D9\u6240"));
|
||||
// Reported as bug report.
|
||||
assertEquals("\u8D39", VCardUtils.toStringAsV30ParamValue("\u8D39"));
|
||||
assertEquals("\"comma,separated\"",
|
||||
VCardUtils.toStringAsV30ParamValue("comma,separated"));
|
||||
assertEquals("\"colon:aware\"",
|
||||
VCardUtils.toStringAsV30ParamValue("colon:aware"));
|
||||
// CTL characters.
|
||||
assertEquals("CTLExample",
|
||||
VCardUtils.toStringAsV30ParamValue("CTL\u0001Example"));
|
||||
assertTrue(TextUtils.isEmpty(
|
||||
VCardUtils.toStringAsV30ParamValue("\u0001\u0002\u0003")));
|
||||
// DQUOTE must be removed.
|
||||
assertEquals("quoted",
|
||||
VCardUtils.toStringAsV30ParamValue("\"quoted\""));
|
||||
// DQUOTE must be removed basically, but we should detect a space, which
|
||||
// require us to use DQUOTE again.
|
||||
// Right-side has one more illegal dquote to test quote-handle code thoroughly.
|
||||
assertEquals("\"Already quoted\"",
|
||||
VCardUtils.toStringAsV30ParamValue("\"Already quoted\"\""));
|
||||
}
|
||||
|
||||
public void testAppearsLikeAndroidVCardQuotedPrintableByLength() {
|
||||
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("="));
|
||||
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=1"));
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12"));
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12="));
|
||||
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=1"));
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=12"));
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=12="));
|
||||
}
|
||||
|
||||
public void testAppearsLikeAndroidVCardQuotedPrintableByContent() {
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("==="));
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("===="));
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("======="));
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=12="));
|
||||
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=34="));
|
||||
|
||||
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=123"));
|
||||
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=123="));
|
||||
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("_12="));
|
||||
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12_"));
|
||||
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=34_56="));
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.exception.VCardAgentNotSupportedException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class VCardAgentNotSupportedExceptionTest extends TestCase {
|
||||
static final String TEST_MESSAGE = "message";
|
||||
|
||||
public void testExceptionWithoutMessage() {
|
||||
VCardAgentNotSupportedException exception = new VCardAgentNotSupportedException();
|
||||
assertNull(exception.getMessage());
|
||||
}
|
||||
|
||||
public void testExceptionWithMessage() {
|
||||
VCardAgentNotSupportedException exception = new VCardAgentNotSupportedException(
|
||||
TEST_MESSAGE);
|
||||
assertEquals(exception.getMessage(), TEST_MESSAGE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.exception.VCardException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class VCardExceptionTest extends TestCase {
|
||||
static final String TEST_MESSAGE = "message";
|
||||
|
||||
public void testExceptionWithoutMessage() {
|
||||
VCardException exception = new VCardException();
|
||||
assertNull(exception.getMessage());
|
||||
}
|
||||
|
||||
public void testExceptionWithMessage() {
|
||||
VCardException exception = new VCardException(TEST_MESSAGE);
|
||||
assertEquals(exception.getMessage(), TEST_MESSAGE);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.exception.VCardInvalidCommentLineException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class VCardInvalidCommentLineExceptionTest extends TestCase {
|
||||
static final String TEST_MESSAGE = "message";
|
||||
|
||||
public void testExceptionWithoutMessage() {
|
||||
VCardInvalidCommentLineException exception = new VCardInvalidCommentLineException();
|
||||
assertNull(exception.getMessage());
|
||||
}
|
||||
|
||||
public void testExceptionWithMessage() {
|
||||
VCardInvalidCommentLineException exception = new VCardInvalidCommentLineException(
|
||||
TEST_MESSAGE);
|
||||
assertEquals(exception.getMessage(), TEST_MESSAGE);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.exception.VCardInvalidLineException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class VCardInvalidLineExceptionTest extends TestCase {
|
||||
static final String TEST_MESSAGE = "message";
|
||||
|
||||
public void testExceptionWithoutMessage() {
|
||||
VCardInvalidLineException exception = new VCardInvalidLineException();
|
||||
assertNull(exception.getMessage());
|
||||
}
|
||||
|
||||
public void testExceptionWithMessage() {
|
||||
VCardInvalidLineException exception = new VCardInvalidLineException(TEST_MESSAGE);
|
||||
assertEquals(exception.getMessage(), TEST_MESSAGE);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.exception.VCardNestedException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class VCardNestedExceptionTest extends TestCase {
|
||||
static final String TEST_MESSAGE = "message";
|
||||
|
||||
public void testExceptionWithoutMessage() {
|
||||
VCardNestedException exception = new VCardNestedException();
|
||||
assertNull(exception.getMessage());
|
||||
}
|
||||
|
||||
public void testExceptionWithMessage() {
|
||||
VCardNestedException exception = new VCardNestedException(TEST_MESSAGE);
|
||||
assertEquals(exception.getMessage(), TEST_MESSAGE);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.exception.VCardNotSupportedException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class VCardNotSupportedExceptionTest extends TestCase {
|
||||
static final String TEST_MESSAGE = "message";
|
||||
|
||||
public void testExceptionWithoutMessage() {
|
||||
VCardNotSupportedException exception = new VCardNotSupportedException();
|
||||
assertNull(exception.getMessage());
|
||||
}
|
||||
|
||||
public void testExceptionWithMessage() {
|
||||
VCardNotSupportedException exception = new VCardNotSupportedException(TEST_MESSAGE);
|
||||
assertEquals(exception.getMessage(), TEST_MESSAGE);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vcard.tests;
|
||||
|
||||
import com.android.vcard.exception.VCardVersionException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class VCardVersionExceptionTest extends TestCase {
|
||||
static final String TEST_MESSAGE = "message";
|
||||
|
||||
public void testExceptionWithoutMessage() {
|
||||
VCardVersionException exception = new VCardVersionException();
|
||||
assertNull(exception.getMessage());
|
||||
}
|
||||
|
||||
public void testExceptionWithMessage() {
|
||||
VCardVersionException exception = new VCardVersionException(TEST_MESSAGE);
|
||||
assertEquals(exception.getMessage(), TEST_MESSAGE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.android.vcard.tests.testutils;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.provider.ContactsContract.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The class representing one contact, which should contain multiple ContentValues like
|
||||
* StructuredName, Email, etc.
|
||||
* </p>
|
||||
*/
|
||||
public final class ContactEntry {
|
||||
private final List<ContentValues> mContentValuesList = new ArrayList<ContentValues>();
|
||||
|
||||
public ContentValuesBuilder addContentValues(String mimeType) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(Data.MIMETYPE, mimeType);
|
||||
mContentValuesList.add(contentValues);
|
||||
return new ContentValuesBuilder(contentValues);
|
||||
}
|
||||
|
||||
public List<ContentValues> getList() {
|
||||
return mContentValuesList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests.testutils;
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
/**
|
||||
* ContentValues-like class which enables users to chain put() methods and restricts
|
||||
* the other methods.
|
||||
*/
|
||||
public class ContentValuesBuilder {
|
||||
private final ContentValues mContentValues;
|
||||
|
||||
public ContentValuesBuilder(final ContentValues contentValues) {
|
||||
mContentValues = contentValues;
|
||||
}
|
||||
|
||||
public ContentValuesBuilder put(String key, String value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
public ContentValuesBuilder put(String key, Byte value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentValuesBuilder put(String key, Short value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}*/
|
||||
|
||||
public ContentValuesBuilder put(String key, Integer value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
public ContentValuesBuilder put(String key, Long value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentValuesBuilder put(String key, Float value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentValuesBuilder put(String key, Double value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentValuesBuilder put(String key, Boolean value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}*/
|
||||
|
||||
public ContentValuesBuilder put(String key, byte[] value) {
|
||||
mContentValues.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentValuesBuilder putNull(String key) {
|
||||
mContentValues.putNull(key);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests.testutils;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import com.android.vcard.VCardEntry;
|
||||
import com.android.vcard.VCardEntryHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ContentValuesVerifier implements VCardEntryHandler {
|
||||
private List<ContentValuesVerifierElem> mContentValuesVerifierElemList =
|
||||
new ArrayList<ContentValuesVerifierElem>();
|
||||
private int mIndex;
|
||||
|
||||
public ContentValuesVerifierElem addElem(AndroidTestCase androidTestCase) {
|
||||
ContentValuesVerifierElem elem = new ContentValuesVerifierElem(androidTestCase);
|
||||
mContentValuesVerifierElemList.add(elem);
|
||||
return elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
|
||||
elem.onParsingStart();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryCreated(VCardEntry entry) {
|
||||
AndroidTestCase.assertTrue(mIndex < mContentValuesVerifierElemList.size());
|
||||
mContentValuesVerifierElemList.get(mIndex).onEntryCreated(entry);
|
||||
mIndex++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd() {
|
||||
for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
|
||||
elem.onParsingEnd();
|
||||
elem.verifyResolver();
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests.testutils;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import com.android.vcard.VCardEntry;
|
||||
import com.android.vcard.VCardEntryCommitter;
|
||||
import com.android.vcard.VCardEntryHandler;
|
||||
|
||||
public class ContentValuesVerifierElem {
|
||||
private final ImportTestResolver mResolver;
|
||||
private final VCardEntryHandler mHandler;
|
||||
|
||||
public ContentValuesVerifierElem(AndroidTestCase androidTestCase) {
|
||||
mResolver = new ImportTestResolver(androidTestCase);
|
||||
mHandler = new VCardEntryCommitter(mResolver);
|
||||
}
|
||||
|
||||
public ContentValuesBuilder addExpected(String mimeType) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(Data.MIMETYPE, mimeType);
|
||||
mResolver.addExpectedContentValues(contentValues);
|
||||
return new ContentValuesBuilder(contentValues);
|
||||
}
|
||||
|
||||
public void verifyResolver() {
|
||||
mResolver.verify();
|
||||
}
|
||||
|
||||
public void onParsingStart() {
|
||||
mHandler.onStart();
|
||||
}
|
||||
|
||||
public void onEntryCreated(VCardEntry entry) {
|
||||
mHandler.onEntryCreated(entry);
|
||||
}
|
||||
|
||||
public void onParsingEnd() {
|
||||
mHandler.onEnd();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.android.vcard.tests.testutils;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Entity;
|
||||
import android.content.EntityIterator;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.mock.MockContentProvider;
|
||||
import android.test.mock.MockCursor;
|
||||
import android.util.Log;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ExportTestProvider extends MockContentProvider {
|
||||
final private ArrayList<ContactEntry> mContactEntryList = new ArrayList<ContactEntry>();
|
||||
|
||||
private static class MockEntityIterator implements EntityIterator {
|
||||
private final List<Entity> mEntityList;
|
||||
private Iterator<Entity> mIterator;
|
||||
|
||||
public MockEntityIterator() {
|
||||
mEntityList = new ArrayList<Entity>();
|
||||
mIterator = mEntityList.iterator();
|
||||
}
|
||||
|
||||
public void add(List<ContentValues> contentValuesList) {
|
||||
Entity entity = new Entity(new ContentValues());
|
||||
for (ContentValues contentValues : contentValuesList) {
|
||||
entity.addSubValue(Data.CONTENT_URI, contentValues);
|
||||
}
|
||||
mEntityList.add(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return mIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity next() {
|
||||
return mIterator.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("remove not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mIterator = mEntityList.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
|
||||
public ExportTestProvider(AndroidTestCase androidTestCase) {
|
||||
}
|
||||
|
||||
public ContactEntry buildInputEntry() {
|
||||
ContactEntry contactEntry = new ContactEntry();
|
||||
mContactEntryList.add(contactEntry);
|
||||
return contactEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An old method which had existed but was removed from ContentResolver.
|
||||
* </p>
|
||||
* <p>
|
||||
* We still keep using this method since we don't have a propeer way to know
|
||||
* which value in the ContentValue corresponds to the entry in Contacts database.
|
||||
* </p>
|
||||
*/
|
||||
public EntityIterator queryEntities(Uri uri,
|
||||
String selection, String[] selectionArgs, String sortOrder) {
|
||||
TestCase.assertTrue(uri != null);
|
||||
TestCase.assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
|
||||
final String authority = uri.getAuthority();
|
||||
TestCase.assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority));
|
||||
TestCase.assertTrue(selection != null);
|
||||
TestCase.assertTrue((selection.contains(Data.CONTACT_ID + " IN ")));
|
||||
TestCase.assertNull(selectionArgs);
|
||||
|
||||
MockEntityIterator iterator = new MockEntityIterator();
|
||||
for (ContactEntry contactEntry : mContactEntryList) {
|
||||
iterator.add(contactEntry.getList());
|
||||
}
|
||||
iterator.reset();
|
||||
return iterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri,String[] projection,
|
||||
String selection, String[] selectionArgs, String sortOrder) {
|
||||
TestCase.assertTrue(VCardVerifier.CONTACTS_TEST_CONTENT_URI.equals(uri));
|
||||
// In this test, following arguments are not supported.
|
||||
TestCase.assertNull(selection);
|
||||
TestCase.assertNull(selectionArgs);
|
||||
TestCase.assertNull(sortOrder);
|
||||
|
||||
return new MockCursor() {
|
||||
int mCurrentPosition = -1;
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mContactEntryList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToFirst() {
|
||||
mCurrentPosition = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToNext() {
|
||||
if (mCurrentPosition < mContactEntryList.size() - 1) {
|
||||
mCurrentPosition++;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBeforeFirst() {
|
||||
return mCurrentPosition < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLast() {
|
||||
return mCurrentPosition == mContactEntryList.size() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfterLast() {
|
||||
return mCurrentPosition >= mContactEntryList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnIndex(String columnName) {
|
||||
TestCase.assertEquals(Data.CONTACT_ID, columnName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int columnIndex) {
|
||||
TestCase.assertEquals(0, columnIndex);
|
||||
TestCase.assertTrue(mCurrentPosition >= 0
|
||||
&& mCurrentPosition < mContactEntryList.size());
|
||||
return mCurrentPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int columnIndex) {
|
||||
return getInt(columnIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(int columnIndex) {
|
||||
return String.valueOf(getInt(columnIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.android.vcard.tests.testutils;
|
||||
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.mock.MockContentResolver;
|
||||
|
||||
public class ExportTestResolver extends MockContentResolver {
|
||||
private final ExportTestProvider mProvider;
|
||||
public ExportTestResolver(AndroidTestCase androidTestCase) {
|
||||
mProvider = new ExportTestProvider(androidTestCase);
|
||||
addProvider(VCardVerifier.VCARD_TEST_AUTHORITY, mProvider);
|
||||
addProvider(RawContacts.CONTENT_URI.getAuthority(), mProvider);
|
||||
}
|
||||
|
||||
public ContactEntry addInputContactEntry() {
|
||||
return mProvider.buildInputEntry();
|
||||
}
|
||||
|
||||
public ExportTestProvider getProvider() {
|
||||
return mProvider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests.testutils;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentValues;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.test.mock.MockContentProvider;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class ImportTestProvider extends MockContentProvider {
|
||||
private final Map<String, Collection<ContentValues>>
|
||||
mMimeTypeToExpectedContentValues = new HashMap<String, Collection<ContentValues>>();
|
||||
|
||||
public void addExpectedContentValues(ContentValues expectedContentValues) {
|
||||
final String mimeType = expectedContentValues.getAsString(Data.MIMETYPE);
|
||||
|
||||
final Collection<ContentValues> contentValuesCollection;
|
||||
if (mMimeTypeToExpectedContentValues.containsKey(mimeType)) {
|
||||
contentValuesCollection = mMimeTypeToExpectedContentValues.get(mimeType);
|
||||
} else {
|
||||
contentValuesCollection = new ArrayList<ContentValues>();
|
||||
mMimeTypeToExpectedContentValues.put(mimeType, contentValuesCollection);
|
||||
}
|
||||
|
||||
contentValuesCollection.add(expectedContentValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentProviderResult[] applyBatch(
|
||||
ArrayList<ContentProviderOperation> operations) {
|
||||
if (operations == null) {
|
||||
TestCase.fail("There is no operation.");
|
||||
}
|
||||
|
||||
final int size = operations.size();
|
||||
ContentProviderResult[] fakeResultArray = new ContentProviderResult[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
Uri uri = Uri.withAppendedPath(RawContacts.CONTENT_URI, String.valueOf(i));
|
||||
fakeResultArray[i] = new ContentProviderResult(uri);
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
ContentProviderOperation operation = operations.get(i);
|
||||
ContentValues contentValues = operation.resolveValueBackReferences(
|
||||
fakeResultArray, i);
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
ContentProviderOperation operation = operations.get(i);
|
||||
ContentValues actualContentValues = operation.resolveValueBackReferences(
|
||||
fakeResultArray, i);
|
||||
final Uri uri = operation.getUri();
|
||||
if (uri.equals(RawContacts.CONTENT_URI)) {
|
||||
TestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_NAME));
|
||||
TestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_TYPE));
|
||||
} else if (uri.equals(Data.CONTENT_URI)) {
|
||||
final String mimeType = actualContentValues.getAsString(Data.MIMETYPE);
|
||||
if (!mMimeTypeToExpectedContentValues.containsKey(mimeType)) {
|
||||
TestCase.fail("Unregistered MimeType " + mimeType);
|
||||
}
|
||||
// Remove data meaningless in this unit tests.
|
||||
// Specifically, Data.DATA1 - DATA7 are set to null or empty String
|
||||
// regardless of the input, but it may change depending on how
|
||||
// resolver-related code handles it.
|
||||
// Here, we ignore these implementation-dependent specs and
|
||||
// just check whether vCard importer correctly inserts rellevent data.
|
||||
Set<String> keyToBeRemoved = new HashSet<String>();
|
||||
for (Entry<String, Object> entry : actualContentValues.valueSet()) {
|
||||
Object value = entry.getValue();
|
||||
if (value == null || TextUtils.isEmpty(value.toString())) {
|
||||
keyToBeRemoved.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
for (String key: keyToBeRemoved) {
|
||||
actualContentValues.remove(key);
|
||||
}
|
||||
/* for testing
|
||||
Log.d("@@@",
|
||||
String.format("MimeType: %s, data: %s",
|
||||
mimeType, actualContentValues.toString())); */
|
||||
// Remove RAW_CONTACT_ID entry just for safety, since we do not care
|
||||
// how resolver-related code handles the entry in this unit test,
|
||||
if (actualContentValues.containsKey(Data.RAW_CONTACT_ID)) {
|
||||
actualContentValues.remove(Data.RAW_CONTACT_ID);
|
||||
}
|
||||
final Collection<ContentValues> contentValuesCollection =
|
||||
mMimeTypeToExpectedContentValues.get(mimeType);
|
||||
if (contentValuesCollection.isEmpty()) {
|
||||
TestCase.fail("ContentValues for MimeType " + mimeType
|
||||
+ " is not expected at all (" + actualContentValues + ")");
|
||||
}
|
||||
boolean checked = false;
|
||||
for (ContentValues expectedContentValues : contentValuesCollection) {
|
||||
/*for testing
|
||||
Log.d("@@@", "expected: "
|
||||
+ convertToEasilyReadableString(expectedContentValues));
|
||||
Log.d("@@@", "actual : "
|
||||
+ convertToEasilyReadableString(actualContentValues));*/
|
||||
if (equalsForContentValues(expectedContentValues,
|
||||
actualContentValues)) {
|
||||
TestCase.assertTrue(contentValuesCollection.remove(expectedContentValues));
|
||||
checked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!checked) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("\n");
|
||||
builder.append("Unexpected: ");
|
||||
builder.append(convertToEasilyReadableString(actualContentValues));
|
||||
builder.append("\n");
|
||||
builder.append("Expected : ");
|
||||
for (ContentValues expectedContentValues : contentValuesCollection) {
|
||||
builder.append(convertToEasilyReadableString(expectedContentValues));
|
||||
}
|
||||
TestCase.fail(builder.toString());
|
||||
}
|
||||
} else {
|
||||
TestCase.fail("Unexpected Uri has come: " + uri);
|
||||
}
|
||||
} // for (int i = 0; i < size; i++) {
|
||||
return fakeResultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all expected ContentValues are consumed during import.
|
||||
*/
|
||||
public void verify() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Collection<ContentValues> contentValuesCollection :
|
||||
mMimeTypeToExpectedContentValues.values()) {
|
||||
for (ContentValues expectedContentValues: contentValuesCollection) {
|
||||
builder.append(convertToEasilyReadableString(expectedContentValues));
|
||||
builder.append("\n");
|
||||
}
|
||||
}
|
||||
if (builder.length() > 0) {
|
||||
final String failMsg =
|
||||
"There is(are) remaining expected ContentValues instance(s): \n"
|
||||
+ builder.toString();
|
||||
TestCase.fail(failMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to print ContentValues whose content is printed with sorted keys.
|
||||
*/
|
||||
private String convertToEasilyReadableString(ContentValues contentValues) {
|
||||
if (contentValues == null) {
|
||||
return "null";
|
||||
}
|
||||
String mimeTypeValue = "";
|
||||
SortedMap<String, String> sortedMap = new TreeMap<String, String>();
|
||||
for (Entry<String, Object> entry : contentValues.valueSet()) {
|
||||
final String key = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
final String valueString = (value != null ? value.toString() : null);
|
||||
if (Data.MIMETYPE.equals(key)) {
|
||||
mimeTypeValue = valueString;
|
||||
} else {
|
||||
TestCase.assertNotNull(key);
|
||||
sortedMap.put(key, valueString);
|
||||
}
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(Data.MIMETYPE);
|
||||
builder.append('=');
|
||||
builder.append(mimeTypeValue);
|
||||
for (Entry<String, String> entry : sortedMap.entrySet()) {
|
||||
final String key = entry.getKey();
|
||||
final String value = entry.getValue();
|
||||
builder.append(' ');
|
||||
builder.append(key);
|
||||
builder.append("=\"");
|
||||
builder.append(value);
|
||||
builder.append('"');
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static boolean equalsForContentValues(
|
||||
final ContentValues expected, final ContentValues actual) {
|
||||
if (expected == actual) {
|
||||
return true;
|
||||
} else if (expected == null || actual == null || expected.size() != actual.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Entry<String, Object> entry : expected.valueSet()) {
|
||||
final String key = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
if (!actual.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
// Type mismatch usuall happens as importer doesn't care the type of each value.
|
||||
// For example, variable type might be Integer when importing the type of TEL,
|
||||
// while variable type would be String when importing the type of RELATION.
|
||||
final Object actualValue = actual.get(key);
|
||||
if (value instanceof byte[]) {
|
||||
if (!Arrays.equals((byte[])value, (byte[])actualValue)) {
|
||||
byte[] e = (byte[])value;
|
||||
byte[] a = (byte[])actualValue;
|
||||
return false;
|
||||
}
|
||||
} else if (!value.equals(actualValue) &&
|
||||
!value.toString().equals(actualValue.toString())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.vcard.tests.testutils;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentValues;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.mock.MockContentResolver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ImportTestResolver extends MockContentResolver {
|
||||
private final ImportTestProvider mProvider;
|
||||
|
||||
public ImportTestResolver(AndroidTestCase androidTestCase) {
|
||||
mProvider = new ImportTestProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentProviderResult[] applyBatch(String authority,
|
||||
ArrayList<ContentProviderOperation> operations) {
|
||||
equalsString(authority, RawContacts.CONTENT_URI.toString());
|
||||
return mProvider.applyBatch(operations);
|
||||
}
|
||||
|
||||
public void addExpectedContentValues(ContentValues expectedContentValues) {
|
||||
mProvider.addExpectedContentValues(expectedContentValues);
|
||||
}
|
||||
|
||||
public void verify() {
|
||||
mProvider.verify();
|
||||
}
|
||||
|
||||
private static boolean equalsString(String a, String b) {
|
||||
if (a == null || a.length() == 0) {
|
||||
return b == null || b.length() == 0;
|
||||
} else {
|
||||
return a.equals(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user