rhodes 2.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG +6 -0
  2. data/Manifest.txt +3 -1
  3. data/bin/rhodes-setup +1 -32
  4. data/lib/framework/erb.rb +3 -3
  5. data/lib/framework/rhodes.rb +2 -2
  6. data/lib/framework/version.rb +2 -2
  7. data/lib/rhodes.rb +2 -2
  8. data/platform/android/Rhodes/AndroidManifest.xml +3 -2
  9. data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_Rhodes.h +2 -2
  10. data/platform/android/Rhodes/jni/src/rhodes.cpp +7 -5
  11. data/platform/android/Rhodes/src/com/rhomobile/rhodes/Capabilities.java +2 -0
  12. data/platform/android/Rhodes/src/com/rhomobile/rhodes/Rhodes.java +15 -6
  13. data/platform/android/Rhodes/src/com/rhomobile/rhodes/camera/ImageCapture.java +5 -2
  14. data/platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/Contact.java +8 -2
  15. data/platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactAccessor.java +11 -0
  16. data/platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactAccessorNew.java +310 -0
  17. data/platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactAccessorOld.java +275 -0
  18. data/platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/Phonebook.java +125 -322
  19. data/platform/android/build/RhodesSRC_build.files +23 -21
  20. data/platform/android/build/android.rake +40 -17
  21. data/platform/iphone/Info.plist +1 -1
  22. data/platform/iphone/rbuild/iphone.rake +58 -33
  23. data/platform/iphone/rhorunner.xcodeproj/project.pbxproj +1 -1
  24. data/platform/shared/common/RhoPort.h +18 -3
  25. data/platform/shared/common/RhodesApp.cpp +76 -54
  26. data/platform/shared/common/StringConverter.h +3 -2
  27. data/platform/shared/common/stat.h +29 -4
  28. data/platform/shared/db/DBAdapter.cpp +2 -1
  29. data/platform/shared/db/DBAdapter.h +1 -1
  30. data/platform/shared/json/RJSONTokener.c +1 -1
  31. data/platform/shared/json/json_object.c +2 -2
  32. data/platform/shared/json/json_tokener.c +1 -1
  33. data/rhodes.gemspec +1 -1
  34. data/spec/phone_spec/app/Spec/contacts_spec.rb +10 -3
  35. data/spec/phone_spec/app/Spec/controller.rb +3 -3
  36. data/spec/phone_spec/app/Spec/mapview_spec.rb +3 -1
  37. data/spec/phone_spec/build.yml +2 -1
  38. metadata +6 -4
  39. data/rhobuild.yml +0 -39
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ ## 2.0.1
2
+ * #4049590 - Android 2.2, rhodes rc2: take picture hangs
3
+ * #4103477 - Android 2.2: can't write to DB
4
+ * #3985537 - Android: cannot build with 2.2 sdk only
5
+ * #4038658 - Get free listening port on iphone
6
+
1
7
  ## 2.0.0
2
8
  * #4053947 - Android: FindClass always return NULL when called outside of JNI_OnLoad
3
9
  * #4060638 - reset functions don't wipe client_id
@@ -342,6 +342,9 @@ platform/android/Rhodes/src/com/rhomobile/rhodes/NavBar.java
342
342
  platform/android/Rhodes/src/com/rhomobile/rhodes/NetworkConnectivityListener.java
343
343
  platform/android/Rhodes/src/com/rhomobile/rhodes/NetworkStateTracker.java
344
344
  platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/Contact.java
345
+ platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactAccessor.java
346
+ platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactAccessorNew.java
347
+ platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactAccessorOld.java
345
348
  platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactField.java
346
349
  platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/Phonebook.java
347
350
  platform/android/Rhodes/src/com/rhomobile/rhodes/RhoConf.java
@@ -3550,7 +3553,6 @@ res/generators/templates/spec/app/mspec.rb
3550
3553
  res/generators/templates/spec/app/spec_runner.rb
3551
3554
  res/generators/templates/spec/app/SpecRunner/controller.rb
3552
3555
  res/generators/templates/spec/app/SpecRunner/index.erb
3553
- rhobuild.yml
3554
3556
  rhobuild.yml.example
3555
3557
  rhodes.gemspec
3556
3558
  spec/framework_spec/app/Account/account.rb
@@ -55,38 +55,7 @@ if ENV['ANDROID_HOME']
55
55
  android = ENV['ANDROID_HOME']
56
56
  end
57
57
 
58
- while true
59
- android = prompt_for("Android SDK path", android, false)
60
- break if android.nil?
61
-
62
- android = android.gsub(/\\/,"/")
63
- apilevel = -1
64
- android_platform_dir = "/platforms/android-1.5"
65
- Dir.glob(File.join(android, 'platforms', '*')).each do |dir|
66
- props = File.join(dir, 'source.properties')
67
- next unless File.file? props
68
- File.open(props, 'r') do |f|
69
- while line = f.gets
70
- next if line !~ /^\s*AndroidVersion\.ApiLevel\s*=\s*([0-9]+)\s*$/
71
- apilevel = $1.to_i
72
- break
73
- end
74
- end
75
-
76
- if apilevel == 3
77
- android_platform_dir = dir[android.length..-1]
78
- break
79
- end
80
- end
81
- android = "" if apilevel == -1
82
-
83
- unless File.directory? File.join(android, android_platform_dir)
84
- puts "Invalid Android SDK path"
85
- next
86
- end
87
-
88
- break
89
- end
58
+ android = prompt_for("Android SDK path", android, false)
90
59
 
91
60
  # try to detect android ndk
92
61
  ndk = ""
@@ -750,11 +750,11 @@ class ERB
750
750
  # setup of an ERB _compiler_ object.
751
751
  #
752
752
  def set_eoutvar(compiler, eoutvar = '_erbout')
753
- compiler.put_cmd = "#{eoutvar}.concat"
754
- compiler.insert_cmd = "#{eoutvar}.concat"
753
+ compiler.put_cmd = "#{eoutvar}.force_encoding('utf-8');#{eoutvar}.concat"
754
+ compiler.insert_cmd = "#{eoutvar}.force_encoding('utf-8');#{eoutvar}.concat"
755
755
 
756
756
  cmd = []
757
- cmd.push "#{eoutvar} = ''"
757
+ cmd.push "#{eoutvar} = '';#{eoutvar}.force_encoding('utf-8')"
758
758
 
759
759
  compiler.pre_cmd = cmd
760
760
 
@@ -1,9 +1,9 @@
1
1
  module Rhodes
2
2
  unless defined? Rhodes::VERSION
3
- VERSION = '2.0.0'
3
+ VERSION = '2.0.2'
4
4
  end
5
5
  unless defined? Rhodes::DBVERSION
6
- DBVERSION = '2.0.5'
6
+ DBVERSION = '2.0.2'
7
7
  end
8
8
 
9
9
  end
@@ -1,8 +1,8 @@
1
1
  module RhodesFramework
2
2
  unless defined? RhodesFramework::VERSION
3
- VERSION = '2.0.0'
3
+ VERSION = '2.0.2'
4
4
  end
5
5
  unless defined? RhodesFramework::DBVERSION
6
- DBVERSION = '2.0.0'
6
+ DBVERSION = '2.0.2'
7
7
  end
8
8
  end
@@ -1,9 +1,9 @@
1
1
  module Rhodes
2
2
  unless defined? Rhodes::VERSION
3
- VERSION = '2.0.0'
3
+ VERSION = '2.0.2'
4
4
  end
5
5
  unless defined? Rhodes::DBVERSION
6
- DBVERSION = '2.0.5'
6
+ DBVERSION = '2.0.2'
7
7
  end
8
8
 
9
9
  end
@@ -1,8 +1,8 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
3
  package="com.rhomobile.rhodes"
4
- android:versionCode="20"
5
- android:versionName="2.0.0">
4
+ android:versionCode="22"
5
+ android:versionName="2.0.2">
6
6
  <uses-sdk android:minSdkVersion="3" />
7
7
  <application android:icon="@drawable/icon"
8
8
  android:multiprocess="true"
@@ -35,4 +35,5 @@
35
35
  <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
36
36
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
37
37
  <uses-permission android:name="android.permission.VIBRATE" />
38
+ <uses-permission android:name="android.permission.GET_ACCOUNTS" />
38
39
  </manifest>
@@ -16,10 +16,10 @@ extern "C" {
16
16
  /*
17
17
  * Class: com_rhomobile_rhodes_Rhodes
18
18
  * Method: createRhodesApp
19
- * Signature: (Ljava/lang/String;)V
19
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
20
20
  */
21
21
  JNIEXPORT void JNICALL Java_com_rhomobile_rhodes_Rhodes_createRhodesApp
22
- (JNIEnv *, jobject, jstring);
22
+ (JNIEnv *, jobject, jstring, jstring);
23
23
 
24
24
  /*
25
25
  * Class: com_rhomobile_rhodes_Rhodes
@@ -20,7 +20,8 @@ const char *rho_java_class[] = {
20
20
  #undef RHODES_DEFINE_JAVA_CLASS
21
21
  };
22
22
 
23
- static rho::String g_rootPath;
23
+ static std::string g_root_path;
24
+ static std::string g_sqlite_journals_path;
24
25
 
25
26
  static pthread_key_t g_thrkey;
26
27
 
@@ -179,7 +180,7 @@ jmethodID getJNIClassStaticMethod(JNIEnv *env, jclass cls, const char *name, con
179
180
 
180
181
  const char* rho_native_rhopath()
181
182
  {
182
- return g_rootPath.c_str();
183
+ return g_root_path.c_str();
183
184
  }
184
185
 
185
186
  jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
@@ -328,14 +329,15 @@ RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_Rhodes_initClassLoader
328
329
  }
329
330
 
330
331
  RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_Rhodes_createRhodesApp
331
- (JNIEnv *env, jobject, jstring path)
332
+ (JNIEnv *env, jobject, jstring root_path, jstring sqlite_journals_path)
332
333
  {
333
334
  if (!set_capabilities(env)) return;
334
335
 
335
- g_rootPath = rho_cast<std::string>(path);
336
+ g_root_path = rho_cast<std::string>(root_path);
337
+ g_sqlite_journals_path = rho_cast<std::string>(sqlite_journals_path);
336
338
 
337
339
  // Init SQLite temp directory
338
- sqlite3_temp_directory = (char*)"/sqlite_stmt_journals";
340
+ sqlite3_temp_directory = (char*)g_sqlite_journals_path.c_str();
339
341
 
340
342
  const char* szRootPath = rho_native_rhopath();
341
343
 
@@ -2,11 +2,13 @@ package com.rhomobile.rhodes;
2
2
 
3
3
  public class Capabilities {
4
4
 
5
+ public static boolean AUDIO_ENABLED = true;
5
6
  public static boolean CAMERA_ENABLED = true;
6
7
  public static boolean GPS_ENABLED = true;
7
8
  public static boolean NETWORK_STATE_ENABLED = true;
8
9
  public static boolean PHONE_ENABLED = true;
9
10
  public static boolean PIM_ENABLED = true;
11
+ public static boolean RECORD_AUDIO_ENABLED = true;
10
12
  public static boolean VIBRATE_ENABLED = true;
11
13
 
12
14
  }
@@ -120,7 +120,7 @@ public class Rhodes extends Activity {
120
120
 
121
121
  private String rootPath = null;
122
122
 
123
- public native void createRhodesApp(String path);
123
+ public native void createRhodesApp(String rootPath, String sqliteJournalsPath);
124
124
  public native void startRhodesApp();
125
125
  public native void stopRhodesApp();
126
126
 
@@ -155,17 +155,26 @@ public class Rhodes extends Activity {
155
155
  return rootPath;
156
156
  }
157
157
 
158
- private String phoneMemoryRootPath() {
158
+ private ApplicationInfo getAppInfo() {
159
159
  String pkgName = getPackageName();
160
160
  try {
161
161
  ApplicationInfo info = getPackageManager().getApplicationInfo(pkgName, 0);
162
- String path = info.dataDir + "/rhodata/";
163
- return path;
162
+ return info;
164
163
  } catch (NameNotFoundException e) {
165
164
  throw new RuntimeException("Internal error: package " + pkgName + " not found: " + e.getMessage());
166
165
  }
167
166
  }
168
167
 
168
+ private String getSqliteJournalsPath() {
169
+ String path = getAppInfo().dataDir + "/sqlite_stmt_journals/";
170
+ new File(path).mkdirs();
171
+ return path;
172
+ }
173
+
174
+ private String phoneMemoryRootPath() {
175
+ return getAppInfo().dataDir + "/rhodata/";
176
+ }
177
+
169
178
  private String sdcardRootPath() {
170
179
  String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
171
180
  String pkgName = getPackageName();
@@ -174,7 +183,7 @@ public class Rhodes extends Activity {
174
183
  }
175
184
 
176
185
  public static String getBlobPath() {
177
- return RhodesInstance.getInstance().getRootPath() + "db/db-files";
186
+ return RhodesInstance.getInstance().getRootPath() + "/db/db-files";
178
187
  }
179
188
 
180
189
  private RhoLogConf m_rhoLogConf = new RhoLogConf();
@@ -491,7 +500,7 @@ public class Rhodes extends Activity {
491
500
  finish();
492
501
  return;
493
502
  }
494
- createRhodesApp(getRootPath());
503
+ createRhodesApp(getRootPath(), getSqliteJournalsPath());
495
504
 
496
505
  boolean fullScreen = true;
497
506
  if (RhoConf.isExist("full_screen"))
@@ -41,6 +41,7 @@ import android.view.SurfaceHolder;
41
41
  import android.view.SurfaceView;
42
42
  import android.view.View;
43
43
  import android.view.Window;
44
+ import android.view.WindowManager;
44
45
  import android.view.View.OnClickListener;
45
46
  import android.widget.ImageButton;
46
47
 
@@ -64,7 +65,7 @@ public class ImageCapture extends Activity implements SurfaceHolder.Callback, On
64
65
  super.onCreate(icicle);
65
66
  Logger.D(TAG, "onCreate");
66
67
  requestWindowFeature(Window.FEATURE_NO_TITLE);
67
- getWindow().setFlags(Rhodes.WINDOW_FLAGS, Rhodes.WINDOW_MASK);
68
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
68
69
  getWindow().setFormat(PixelFormat.TRANSLUCENT);
69
70
  setContentView(AndroidR.layout.camera);
70
71
 
@@ -137,7 +138,9 @@ public class ImageCapture extends Activity implements SurfaceHolder.Callback, On
137
138
  camera.stopPreview();
138
139
  }
139
140
  Camera.Parameters p = camera.getParameters();
140
- p.setPreviewSize(w, h);
141
+ int newW = (w >> 3) << 3;
142
+ int newH = (h >> 3) << 3;
143
+ p.setPreviewSize(newW, newH);
141
144
  camera.setParameters(p);
142
145
  camera.setPreviewDisplay(holder);
143
146
  camera.startPreview();
@@ -26,6 +26,7 @@ import java.util.Map;
26
26
 
27
27
  public class Contact {
28
28
 
29
+ private String id = null;
29
30
  private Map<String, ContactField> fields = new HashMap<String, ContactField>();
30
31
  private Iterator<ContactField> iter = null;
31
32
 
@@ -43,11 +44,16 @@ public class Contact {
43
44
  if ( fields.containsKey(key) )
44
45
  return fields.get(key).getValue();
45
46
 
46
- return "";
47
+ return null;
48
+ }
49
+
50
+ public void setId(String v) {
51
+ id = v;
52
+ setField(Phonebook.PB_ID, "{" + v + "}");
47
53
  }
48
54
 
49
55
  public String id() {
50
- return getField(Phonebook.PB_ID);
56
+ return id;
51
57
  }
52
58
 
53
59
  public void moveToBegin() {
@@ -0,0 +1,11 @@
1
+ package com.rhomobile.rhodes.phonebook;
2
+
3
+ import java.util.Map;
4
+
5
+ public interface ContactAccessor {
6
+
7
+ public Map<String, Contact> getAll() throws Exception;
8
+ public void save(Contact contact) throws Exception;
9
+ public void remove(Contact contact);
10
+
11
+ }
@@ -0,0 +1,310 @@
1
+ package com.rhomobile.rhodes.phonebook;
2
+
3
+ import java.util.HashMap;
4
+ import java.util.Map;
5
+
6
+ import com.rhomobile.rhodes.Rhodes;
7
+ import com.rhomobile.rhodes.RhodesInstance;
8
+
9
+ import android.accounts.Account;
10
+ import android.accounts.AccountManager;
11
+ import android.content.ContentResolver;
12
+ import android.content.ContentUris;
13
+ import android.content.ContentValues;
14
+ import android.database.Cursor;
15
+ import android.net.Uri;
16
+ import android.provider.ContactsContract.CommonDataKinds.Email;
17
+ import android.provider.ContactsContract.CommonDataKinds.Organization;
18
+ import android.provider.ContactsContract.CommonDataKinds.Phone;
19
+ import android.provider.ContactsContract.CommonDataKinds.StructuredName;
20
+ import android.provider.ContactsContract.Data;
21
+ import android.provider.ContactsContract.RawContacts;
22
+
23
+ public class ContactAccessorNew implements ContactAccessor {
24
+
25
+ //private static final String TAG = "ContactsAccessorNew";
26
+
27
+ private static final String PB_ID = Phonebook.PB_ID;
28
+ private static final String PB_FIRST_NAME = Phonebook.PB_FIRST_NAME;
29
+ private static final String PB_LAST_NAME = Phonebook.PB_LAST_NAME;
30
+ private static final String PB_MOBILE_NUMBER = Phonebook.PB_MOBILE_NUMBER;
31
+ private static final String PB_HOME_NUMBER = Phonebook.PB_HOME_NUMBER;
32
+ private static final String PB_BUSINESS_NUMBER = Phonebook.PB_BUSINESS_NUMBER;
33
+ private static final String PB_EMAIL_ADDRESS = Phonebook.PB_EMAIL_ADDRESS;
34
+ private static final String PB_COMPANY_NAME = Phonebook.PB_COMPANY_NAME;
35
+
36
+ private ContentResolver cr;
37
+ private String accName;
38
+ private String accType;
39
+
40
+ public ContactAccessorNew() throws Exception {
41
+ Rhodes r = RhodesInstance.getInstance();
42
+
43
+ Account[] accounts = AccountManager.get(r).getAccounts();
44
+ if (accounts.length == 0) {
45
+ accName = "rhodes@rhomobile.com";
46
+ accType = "com.rhomobile";
47
+ }
48
+ else {
49
+ Account acnt = accounts[0];
50
+ accName = acnt.name;
51
+ accType = acnt.type;
52
+ }
53
+
54
+ cr = r.getContentResolver();
55
+ }
56
+
57
+ private void fillName(String id, Contact contact) {
58
+ contact.setField(PB_FIRST_NAME, "");
59
+ contact.setField(PB_LAST_NAME, "");
60
+
61
+ Cursor cursor = cr.query(Data.CONTENT_URI,
62
+ new String[] {StructuredName.DISPLAY_NAME},
63
+ Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
64
+ new String[] {id, StructuredName.CONTENT_ITEM_TYPE},
65
+ null);
66
+ try {
67
+ if (!cursor.moveToFirst())
68
+ return;
69
+
70
+ String name = cursor.getString(cursor.getColumnIndex(StructuredName.DISPLAY_NAME));
71
+ if (name != null) {
72
+ String[] names = name.split(" ");
73
+ if (names.length == 1) {
74
+ contact.setField(PB_FIRST_NAME, name);
75
+ }
76
+ else {
77
+ contact.setField(PB_FIRST_NAME, names[0]);
78
+ contact.setField(PB_LAST_NAME, names[1]);
79
+ }
80
+ }
81
+ }
82
+ finally {
83
+ cursor.close();
84
+ }
85
+ }
86
+
87
+ private void fillPhones(String id, Contact contact) {
88
+ Cursor cursor = cr.query(Data.CONTENT_URI,
89
+ new String[] {Phone.NUMBER, Phone.TYPE},
90
+ Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
91
+ new String[] {id, Phone.CONTENT_ITEM_TYPE},
92
+ null);
93
+ try {
94
+ if (!cursor.moveToFirst())
95
+ return;
96
+
97
+ int numColumn = cursor.getColumnIndex(Phone.NUMBER);
98
+ int typeColumn = cursor.getColumnIndex(Phone.TYPE);
99
+ do {
100
+ switch (cursor.getInt(typeColumn)) {
101
+ case Phone.TYPE_HOME:
102
+ contact.setField(PB_HOME_NUMBER, cursor.getString(numColumn));
103
+ break;
104
+ case Phone.TYPE_WORK:
105
+ contact.setField(PB_BUSINESS_NUMBER, cursor.getString(numColumn));
106
+ break;
107
+ case Phone.TYPE_MOBILE:
108
+ contact.setField(PB_MOBILE_NUMBER, cursor.getString(numColumn));
109
+ break;
110
+ }
111
+ } while (cursor.moveToNext());
112
+ }
113
+ finally {
114
+ cursor.close();
115
+ }
116
+ }
117
+
118
+ private void fillEmails(String id, Contact contact) {
119
+ Cursor cursor = cr.query(Data.CONTENT_URI,
120
+ new String[] {Email.DATA},
121
+ Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
122
+ new String[] {id, Email.CONTENT_ITEM_TYPE},
123
+ null);
124
+ try {
125
+ if (!cursor.moveToFirst())
126
+ return;
127
+
128
+ String data = cursor.getString(cursor.getColumnIndex(Email.DATA));
129
+ contact.setField(PB_EMAIL_ADDRESS, data);
130
+ }
131
+ finally {
132
+ cursor.close();
133
+ }
134
+ }
135
+
136
+ private void fillCompany(String id, Contact contact) {
137
+ Cursor cursor = cr.query(Data.CONTENT_URI,
138
+ new String[] {Organization.COMPANY},
139
+ Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
140
+ new String[] {id, Organization.CONTENT_ITEM_TYPE},
141
+ null);
142
+ try {
143
+ if (!cursor.moveToFirst())
144
+ return;
145
+ String company = cursor.getString(cursor.getColumnIndex(Organization.COMPANY));
146
+ contact.setField(PB_COMPANY_NAME, company);
147
+ }
148
+ finally {
149
+ cursor.close();
150
+ }
151
+ }
152
+
153
+ public Map<String, Contact> getAll() throws Exception {
154
+ Map<String, Contact> contacts = new HashMap<String, Contact>();
155
+
156
+ Cursor cursor = cr.query(RawContacts.CONTENT_URI,
157
+ new String[] {RawContacts._ID},
158
+ RawContacts.DELETED + "=0", null, null);
159
+ try {
160
+ if (!cursor.moveToFirst())
161
+ return contacts;
162
+
163
+ do {
164
+ Contact contact = new Contact();
165
+
166
+ String id = cursor.getString(cursor.getColumnIndex(RawContacts._ID));
167
+ contact.setId(id);
168
+
169
+ fillName(id, contact);
170
+ fillPhones(id, contact);
171
+ fillEmails(id, contact);
172
+ fillCompany(id, contact);
173
+
174
+ contacts.put(contact.getField(PB_ID), contact);
175
+ } while (cursor.moveToNext());
176
+ }
177
+ finally {
178
+ cursor.close();
179
+ }
180
+
181
+ return contacts;
182
+ }
183
+
184
+ private void create(Contact contact) throws Exception {
185
+ String id = contact.id();
186
+
187
+ if (id == null || id.length() == 0) {
188
+ ContentValues values = new ContentValues();
189
+ values.put(RawContacts.ACCOUNT_NAME, accName);
190
+ values.put(RawContacts.ACCOUNT_TYPE, accType);
191
+ values.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
192
+ Uri uri = cr.insert(RawContacts.CONTENT_URI, values);
193
+ id = String.valueOf(ContentUris.parseId(uri));
194
+ contact.setId(id);
195
+ }
196
+ }
197
+
198
+ private void saveData(Contact contact, ContentValues values, String where, String[] whereValues) throws Exception {
199
+ String id = contact.id();
200
+ values.put(Data.RAW_CONTACT_ID, Long.parseLong(id));
201
+
202
+ // Search is there is already record with the same raw_contact_id and mimetype
203
+ long dataId = 0;
204
+
205
+ StringBuilder w = new StringBuilder();
206
+ w.append(Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?");
207
+ if (where != null)
208
+ w.append(" AND " + where);
209
+ where = w.toString();
210
+
211
+ String mimetype = (String)values.get(Data.MIMETYPE);
212
+ int wvSize = 2;
213
+ if (whereValues != null)
214
+ wvSize += whereValues.length;
215
+ String[] wv = new String[wvSize];
216
+ wv[0] = id;
217
+ wv[1] = mimetype;
218
+ if (whereValues != null)
219
+ System.arraycopy(whereValues, 0, wv, 2, whereValues.length);
220
+
221
+ Cursor cursor = cr.query(Data.CONTENT_URI, new String[] {Data._ID}, where, wv, null);
222
+ try {
223
+ if (cursor.moveToFirst())
224
+ dataId = cursor.getLong(cursor.getColumnIndex(Data._ID));
225
+ }
226
+ finally {
227
+ cursor.close();
228
+ }
229
+
230
+ // Do update if found, insert otherwise
231
+ if (dataId != 0)
232
+ cr.update(Data.CONTENT_URI, values,
233
+ Data._ID + "=?", new String[] {String.valueOf(dataId)});
234
+ else
235
+ cr.insert(Data.CONTENT_URI, values);
236
+ }
237
+
238
+ private void saveData(Contact contact, ContentValues values) throws Exception {
239
+ saveData(contact, values, null, null);
240
+ }
241
+
242
+ private void updateName(Contact contact) throws Exception {
243
+ String firstName = contact.getField(PB_FIRST_NAME);
244
+ String lastName = contact.getField(PB_LAST_NAME);
245
+
246
+ ContentValues values = new ContentValues();
247
+ values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
248
+ values.put(StructuredName.DISPLAY_NAME, firstName + " " + lastName);
249
+ values.put(StructuredName.GIVEN_NAME, firstName);
250
+ values.put(StructuredName.FAMILY_NAME, lastName);
251
+ saveData(contact, values);
252
+ }
253
+
254
+ private void updatePhones(Contact contact) throws Exception {
255
+ String[] phones = {PB_MOBILE_NUMBER, PB_HOME_NUMBER, PB_BUSINESS_NUMBER};
256
+ int[] types = {Phone.TYPE_MOBILE, Phone.TYPE_HOME, Phone.TYPE_WORK};
257
+
258
+ for (int i = 0; i < phones.length; ++i) {
259
+ String phName = phones[i];
260
+ String value = contact.getField(phName);
261
+ if (value == null || value.length() == 0)
262
+ continue;
263
+
264
+ ContentValues values = new ContentValues();
265
+ values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
266
+ values.put(Phone.NUMBER, value);
267
+ values.put(Phone.TYPE, types[i]);
268
+ saveData(contact, values, Phone.TYPE + "=?", new String[] {String.valueOf(types[i])});
269
+ }
270
+ }
271
+
272
+ private void updateEmails(Contact contact) throws Exception {
273
+ String value = contact.getField(PB_EMAIL_ADDRESS);
274
+ if (value == null || value.length() == 0)
275
+ return;
276
+
277
+ ContentValues values = new ContentValues();
278
+ values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
279
+ values.put(Email.DATA, value);
280
+ saveData(contact, values);
281
+ }
282
+
283
+ private void updateCompany(Contact contact) throws Exception {
284
+ String value = contact.getField(PB_COMPANY_NAME);
285
+ if (value == null || value.length() == 0)
286
+ return;
287
+
288
+ ContentValues values = new ContentValues();
289
+ values.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
290
+ values.put(Organization.COMPANY, value);
291
+ saveData(contact, values);
292
+ }
293
+
294
+ public void save(Contact contact) throws Exception {
295
+ create(contact);
296
+
297
+ updateName(contact);
298
+ updatePhones(contact);
299
+ updateEmails(contact);
300
+ updateCompany(contact);
301
+ }
302
+
303
+ public void remove(Contact contact) {
304
+ String id = contact.id();
305
+ if (id == null || id.length() == 0)
306
+ return;
307
+ cr.delete(RawContacts.CONTENT_URI, RawContacts._ID + "=?", new String[] {id});
308
+ }
309
+
310
+ }