Java tutorial
/* * Cos android client for Cozy Cloud * * Copyright (C) 2016 Hamza Abdelkebir * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.codeplumbers.cosi.services; import android.Manifest; import android.app.IntentService; import android.app.NotificationManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.provider.ContactsContract; import android.support.v4.app.ActivityCompat; import android.support.v4.content.WakefulBroadcastReceiver; import android.support.v7.app.NotificationCompat; import android.util.Base64; import android.util.Log; import com.activeandroid.query.Delete; import org.apache.commons.io.IOUtils; import org.greenrobot.eventbus.EventBus; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.List; import eu.codeplumbers.cosi.R; import eu.codeplumbers.cosi.db.models.Contact; import eu.codeplumbers.cosi.db.models.ContactDataPoint; import eu.codeplumbers.cosi.db.models.Device; import eu.codeplumbers.cosi.services.events.CallSyncEvent; import eu.codeplumbers.cosi.services.events.ContactSyncEvent; import eu.codeplumbers.cosi.utils.DateUtils; import eu.codeplumbers.cosi.utils.FileUtils; import static eu.codeplumbers.cosi.utils.Constants.REFRESH; import static eu.codeplumbers.cosi.utils.Constants.SERVICE_ERROR; import static eu.codeplumbers.cosi.utils.Constants.SYNC_MESSAGE; /** * Created by thor on 10/29/16. */ public class CosiContactService extends IntentService { private List<Contact> allContacts; private String errorMessage; private String authHeader; private String designUrl; private String syncUrl; private int notification_id = 1341; private NotificationManager mNotifyManager; private NotificationCompat.Builder mBuilder; private boolean mSyncRunning; private boolean stopSync; public CosiContactService() { super("CosiContactService"); stopSync = false; mSyncRunning = false; } public CosiContactService(String name) { super(name); } @Override protected void onHandleIntent(Intent intent) { // Do the task here Log.i(CosiContactService.class.getName(), "Cosi Service running"); // Release the wake lock provided by the WakefulBroadcastReceiver. WakefulBroadcastReceiver.completeWakefulIntent(intent); allContacts = new ArrayList<>(); Device device = Device.registeredDevice(); // cozy register device url designUrl = device.getUrl() + "/ds-api/request/contact/all/"; syncUrl = device.getUrl() + "/ds-api/data/"; // concatenate username and password with colon for authentication final String credentials = device.getLogin() + ":" + device.getPassword(); authHeader = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); showNotification(); if (isNetworkAvailable()) { try { // read local sms log first readContactDatabase(); EventBus.getDefault().post(new CallSyncEvent(SYNC_MESSAGE, "Getting remote contacts from Cozy...")); getRemoteContacts(); mBuilder.setContentText(getString(R.string.lbl_contacts_sync_done)); mBuilder.setProgress(0, 0, false); mNotifyManager.notify(notification_id, mBuilder.build()); mNotifyManager.cancel(notification_id); sendChangesToCozy(); mNotifyManager.cancel(notification_id); EventBus.getDefault().post(new ContactSyncEvent(REFRESH, "Sync OK")); } catch (Exception e) { e.printStackTrace(); mSyncRunning = false; EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); } } else { mSyncRunning = false; EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, "No Internet connection")); mBuilder.setContentText("Sync failed because no Internet connection was available"); mNotifyManager.notify(notification_id, mBuilder.build()); } } private void readContactDatabase() { //Fetches the complete call log in descending order. i.e recent calls appears first. if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) { ContentResolver cr = getContentResolver(); Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); // // TODO: 11/11/16 remove before release new Delete().from(ContactDataPoint.class).execute(); new Delete().from(Contact.class).execute(); if (cur.getCount() > 0) { int cnt = 0, total = cur.getCount(); while (cur.moveToNext()) { EventBus.getDefault().post(new ContactSyncEvent(SYNC_MESSAGE, "Reading local contacts " + (cnt + 1) + "/" + total + "...")); String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID)); String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); String photo = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI)); System.out.println("name : " + name + ", ID : " + id); //Contact contact = Contact.getByName(name); //if (contact == null) { Contact contact = new Contact(); contact.setN(name); contact.setRevision(DateUtils.formatDate(new Date().getTime())); contact.setRemoteId(""); contact.setTags(new JSONArray().toString()); contact.setFn(name); if (photo != null) { contact.setPhotoBase64(FileUtils.uriToBase64(this, photo)); } else { contact.setPhotoBase64(""); } //} else { if ((contact.getPhotoBase64() == null || contact.getPhotoBase64().equalsIgnoreCase("")) && photo != null) { contact.setPhotoBase64(FileUtils.uriToBase64(this, photo)); } //} contact.setSystemId(id); contact.setDeviceId(contact.getRemoteId().isEmpty() ? Device.registeredDevice().getLogin() : contact.getDeviceId()); contact.save(); if (Integer.parseInt( cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) { // get the phone number Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null); while (pCur.moveToNext()) { String phone = pCur .getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); System.out.println("phone " + phone); if (!phone.isEmpty()) { ContactDataPoint contactDataPoint = ContactDataPoint.getByValue(contact, phone); if (contactDataPoint == null) { contactDataPoint = new ContactDataPoint(); contactDataPoint.setPref(false); contactDataPoint.setType("tel"); contactDataPoint.setValue(phone); contactDataPoint.setName("tel"); contactDataPoint.setContact(contact); contactDataPoint.save(); } } } pCur.close(); } // get email and type Cursor emailCur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[] { id }, null); while (emailCur.moveToNext()) { // This would allow you get several email addresses // if the email addresses were stored in an array String email = emailCur .getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)); String emailType = emailCur .getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE)); System.out.println("Email " + email + " Email Type : " + emailType); if (!email.isEmpty()) { ContactDataPoint contactDataPoint = ContactDataPoint.getByValue(contact, email); if (contactDataPoint == null) { contactDataPoint = new ContactDataPoint(); contactDataPoint.setPref(false); contactDataPoint.setType(emailType); contactDataPoint.setValue(email); contactDataPoint.setName("email"); contactDataPoint.setContact(contact); contactDataPoint.save(); } } } emailCur.close(); // Get note....... String noteWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] noteWhereParams = new String[] { id, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE }; Cursor noteCur = cr.query(ContactsContract.Data.CONTENT_URI, null, noteWhere, noteWhereParams, null); if (noteCur.moveToFirst()) { String note = noteCur .getString(noteCur.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE)); System.out.println("Note " + note); if (!note.isEmpty()) { ContactDataPoint contactDataPoint = ContactDataPoint.getByValue(contact, note); if (contactDataPoint == null) { contactDataPoint = new ContactDataPoint(); contactDataPoint.setPref(false); contactDataPoint.setType("note"); contactDataPoint.setValue(note); contactDataPoint.setName("note"); contactDataPoint.setContact(contact); contactDataPoint.save(); } } } noteCur.close(); //Get Postal Address.... String addrWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] addrWhereParams = new String[] { id, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE }; Cursor addrCur = cr.query(ContactsContract.Data.CONTENT_URI, null, null, null, null); while (addrCur.moveToNext()) { String poBox = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POBOX)); String street = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)); String city = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)); String state = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)); String postalCode = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)); String country = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)); String type = addrCur.getString( addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)); } addrCur.close(); // Get Instant Messenger......... String imWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] imWhereParams = new String[] { id, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE }; Cursor imCur = cr.query(ContactsContract.Data.CONTENT_URI, null, imWhere, imWhereParams, null); if (imCur.moveToFirst()) { String imName = imCur .getString(imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)); String imType; imType = imCur.getString(imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.TYPE)); if (!imName.isEmpty()) { ContactDataPoint contactDataPoint = ContactDataPoint.getByValue(contact, imName); if (contactDataPoint == null) { contactDataPoint = new ContactDataPoint(); contactDataPoint.setPref(false); contactDataPoint.setType(imType); contactDataPoint.setValue(imName); contactDataPoint.setName("chat"); contactDataPoint.setContact(contact); contactDataPoint.save(); } } } imCur.close(); // Get Organizations String orgWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] orgWhereParams = new String[] { id, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE }; Cursor orgCur = cr.query(ContactsContract.Data.CONTENT_URI, null, orgWhere, orgWhereParams, null); if (orgCur.moveToFirst()) { String orgName = orgCur.getString( orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DATA)); String title = orgCur.getString( orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE)); } orgCur.close(); cnt++; } } } else { EventBus.getDefault() .post(new ContactSyncEvent(SERVICE_ERROR, getString(R.string.permission_denied_contacts))); } } /** * Make remote request to get all calls stored in Cozy */ public void getRemoteContacts() { URL urlO = null; try { urlO = new URL(designUrl); HttpURLConnection conn = (HttpURLConnection) urlO.openConnection(); conn.setConnectTimeout(5000); conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); conn.setRequestProperty("Authorization", authHeader); conn.setDoInput(true); conn.setRequestMethod("POST"); // read the response int status = conn.getResponseCode(); InputStream in = null; if (status >= HttpURLConnection.HTTP_BAD_REQUEST) { in = conn.getErrorStream(); } else { in = conn.getInputStream(); } StringWriter writer = new StringWriter(); IOUtils.copy(in, writer, "UTF-8"); String result = writer.toString(); JSONArray jsonArray = new JSONArray(result); if (jsonArray != null) { if (jsonArray.length() == 0) { EventBus.getDefault() .post(new ContactSyncEvent(SYNC_MESSAGE, "Your Cozy has no contacts stored.")); Contact.setAllUnsynced(); } else { for (int i = 0; i < jsonArray.length(); i++) { Log.d("Contact", i + ""); EventBus.getDefault().post(new ContactSyncEvent(SYNC_MESSAGE, "Reading contacts on Cozy " + (i + 1) + "/" + jsonArray.length() + "...")); try { JSONObject contactJson = jsonArray.getJSONObject(i).getJSONObject("value"); Contact contact = Contact.getByRemoteId(contactJson.get("_id").toString()); if (contact == null) { contact = Contact.getByName(contactJson.getString("n")); if (contact == null) { contact = new Contact(contactJson); } else { if (contactJson.has("n")) contact.setN(contactJson.getString("n")); else contact.setN(""); if (contactJson.has("fn")) contact.setFn(contactJson.getString("fn")); else contact.setFn(""); if (contactJson.has("revision")) { contact.setRevision(contactJson.getString("revision")); } else { contact.setRevision(DateUtils.formatDate(new Date().getTime())); } if (contactJson.has("tags") && !contactJson.getString("tags").equalsIgnoreCase("")) { contact.setTags(contactJson.getJSONArray("tags").toString()); } else { contact.setTags(new JSONArray().toString()); } contact.setPhotoBase64(""); contact.setAnniversary(""); if (contactJson.has("deviceId")) { contact.setDeviceId(contactJson.getString("deviceId")); } if (contactJson.has("systemId")) { contact.setSystemId(contactJson.getString("systemId")); } contact.setRemoteId(contactJson.getString("_id")); if (contactJson.has("_attachments")) { JSONObject attachment = contactJson.getJSONObject("_attachments"); contact.setAttachments(attachment.toString()); if (attachment.has("picture")) { JSONObject picture = attachment.getJSONObject("picture"); String attachmentName = new String( Base64.decode(picture.getString("digest").replace("md5-", ""), Base64.DEFAULT)); Log.d("Contact", attachmentName); } } contact.save(); if (contactJson.has("datapoints")) { JSONArray datapoints = contactJson.getJSONArray("datapoints"); for (int j = 0; j < datapoints.length(); j++) { JSONObject datapoint = datapoints.getJSONObject(j); String value = datapoint.getString("value"); ContactDataPoint contactDataPoint = ContactDataPoint.getByValue(contact, value); if (contactDataPoint == null && !value.isEmpty()) { contactDataPoint = new ContactDataPoint(); contactDataPoint.setPref(false); contactDataPoint.setType(datapoint.getString("type")); contactDataPoint.setValue(value); contactDataPoint.setName(datapoint.getString("name")); contactDataPoint.setContact(contact); contactDataPoint.save(); } } } } } else { if (contactJson.has("n")) contact.setN(contactJson.getString("n")); else contact.setN(""); if (contactJson.has("fn")) contact.setFn(contactJson.getString("fn")); else contact.setFn(""); if (contactJson.has("revision")) { contact.setRevision(contactJson.getString("revision")); } else { contact.setRevision(DateUtils.formatDate(new Date().getTime())); } if (contactJson.has("tags") && !contactJson.getString("tags").equalsIgnoreCase("")) { contact.setTags(contactJson.getJSONArray("tags").toString()); } else { contact.setTags(new JSONArray().toString()); } contact.setPhotoBase64(""); contact.setAnniversary(""); if (contactJson.has("deviceId")) { contact.setDeviceId(contactJson.getString("deviceId")); } if (contactJson.has("systemId")) { contact.setSystemId(contactJson.getString("systemId")); } contact.setRemoteId(contactJson.getString("_id")); if (contactJson.has("_attachments")) { JSONObject attachment = contactJson.getJSONObject("_attachments"); contact.setAttachments(attachment.toString()); if (attachment.has("picture")) { JSONObject picture = attachment.getJSONObject("picture"); String attachmentName = new String(Base64.decode( picture.getString("digest").replace("md5-", ""), Base64.DEFAULT)); Log.d("Contact", attachmentName); } } contact.save(); if (contactJson.has("datapoints")) { JSONArray datapoints = contactJson.getJSONArray("datapoints"); for (int j = 0; j < datapoints.length(); j++) { JSONObject datapoint = datapoints.getJSONObject(j); String value = datapoint.getString("value"); ContactDataPoint contactDataPoint = ContactDataPoint.getByValue(contact, value); if (contactDataPoint == null && !value.isEmpty()) { contactDataPoint = new ContactDataPoint(); contactDataPoint.setPref(false); contactDataPoint.setType(datapoint.getString("type")); contactDataPoint.setValue(value); contactDataPoint.setName(datapoint.getString("name")); contactDataPoint.setContact(contact); contactDataPoint.save(); } } } } contact.save(); allContacts.add(contact); } catch (JSONException e) { EventBus.getDefault() .post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } } } } else { errorMessage = new JSONObject(result).getString("error"); EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, errorMessage)); stopSelf(); } in.close(); conn.disconnect(); } catch (MalformedURLException e) { EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } catch (ProtocolException e) { EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } catch (IOException e) { EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } catch (JSONException e) { EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } } public void sendChangesToCozy() { List<Contact> unSyncedContacts = Contact.getAllUnsynced(); int i = 0; for (Contact contact : unSyncedContacts) { URL urlO = null; try { JSONObject jsonObject = contact.toJsonObject(); System.out.println(jsonObject.toString()); mBuilder.setProgress(unSyncedContacts.size(), i + 1, false); mBuilder.setContentText("Syncing " + jsonObject.getString("docType") + ":"); mNotifyManager.notify(notification_id, mBuilder.build()); EventBus.getDefault() .post(new ContactSyncEvent(SYNC_MESSAGE, getString(R.string.lbl_contacts_ongoing_sync))); String remoteId = jsonObject.getString("remoteId"); String requestMethod = ""; if (remoteId.isEmpty()) { urlO = new URL(syncUrl); requestMethod = "POST"; } else { urlO = new URL(syncUrl + remoteId + "/"); requestMethod = "PUT"; } HttpURLConnection conn = (HttpURLConnection) urlO.openConnection(); conn.setConnectTimeout(5000); conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); conn.setRequestProperty("Authorization", authHeader); conn.setDoOutput(true); conn.setDoInput(true); conn.setRequestMethod(requestMethod); // set request body jsonObject.remove("remoteId"); long objectId = jsonObject.getLong("id"); jsonObject.remove("id"); OutputStream os = conn.getOutputStream(); os.write(jsonObject.toString().getBytes("UTF-8")); os.flush(); // read the response InputStream in = new BufferedInputStream(conn.getInputStream()); StringWriter writer = new StringWriter(); IOUtils.copy(in, writer, "UTF-8"); String result = writer.toString(); JSONObject jsonObjectResult = new JSONObject(result); if (jsonObjectResult != null && jsonObjectResult.has("_id")) { result = jsonObjectResult.getString("_id"); contact.setRemoteId(result); contact.save(); } in.close(); conn.disconnect(); } catch (MalformedURLException e) { EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } catch (ProtocolException e) { EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } catch (IOException e) { e.printStackTrace(); EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } catch (JSONException e) { EventBus.getDefault().post(new ContactSyncEvent(SERVICE_ERROR, e.getLocalizedMessage())); stopSelf(); } i++; } } private boolean isNetworkAvailable() { ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService( Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); return activeNetworkInfo != null && activeNetworkInfo.isConnected(); } public void showNotification() { mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new NotificationCompat.Builder(this); mBuilder.setContentTitle(getString(R.string.lbl_contacts)) .setContentText(getString(R.string.lbl_notes_ongoing_sync)) .setSmallIcon(R.drawable.ic_call_black_24dp).setOngoing(true); } }