rhodes 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }