package com.malcom.library.android.module.notifications.services; import java.io.File; import java.io.FilenameFilter; import java.net.URL; import java.util.Date; import java.util.HashMap; import java.util.Map; import android.app.IntentService; import android.content.Intent; import android.util.Log; import com.malcom.library.android.module.core.MCMCoreAdapter; import com.malcom.library.android.module.notifications.MCMNotificationModule; import com.malcom.library.android.utils.HttpDateUtils; import com.malcom.library.android.utils.ToolBox; import com.malcom.library.android.utils.ToolBox.HTTP_METHOD; import com.malcom.library.android.utils.encoding.DigestUtils; import com.malcom.library.android.utils.encoding.base64.Base64; /** * Service that delivers the pending acks to malcom server. * * By using a service for this, we avoid the system to destroys * the application if more resources are needed. Operation of * this kind (deliveries) should always be done by using a service. * * We use the IntentService because the advantages explained here: * http://developer.android.com/guide/components/services.html * * @author Malcom Ventures S.L * @since 2012 * */ public class PendingAcksDeliveryService extends IntentService { public PendingAcksDeliveryService() { super("PendingAcksDeliveryService"); } public PendingAcksDeliveryService(String name) { super(name); } @Override protected void onHandleIntent(Intent intent) { String[] pendingAcks = listCachedAcks(); if(pendingAcks!=null && pendingAcks.length>0){ if(ToolBox.network_haveNetworkConnection(getApplicationContext())){ sendCachedAcks(pendingAcks); }else{ Log.i(MCMNotificationModule.TAG,"PendingAcksDeliveryService: no network connection, skipping pending ack."); } } } // AUXILIAR FUNCTIONS ---------------------------------------------------------------------------------------------- private String[] listCachedAcks(){ String filePath = getApplicationContext().getFilesDir().getAbsolutePath();//returns current directory. File appInternalDir = new File(filePath); String[] pendingBeacons = appInternalDir.list(new FilenameFilter(){ public boolean accept(File arg0, String name) { return name.startsWith(MCMNotificationModule.CACHED_ACK_FILE_PREFIX); }}); return pendingBeacons; } private void sendCachedAcks(String[] pendingAcks){ Log.i(MCMNotificationModule.TAG, "PendingAcksDeliveryService: Pending acks to send: " + pendingAcks.length); for(String ack:pendingAcks){ try { byte[] ackBytes = ToolBox.storage_readDataFromInternalStorage(getApplicationContext(), ack); if(ackBytes!=null && ackBytes.length>0){ sendToMalcom(new String(ackBytes)); } ToolBox.storage_deleteDataFromInternalStorage(getApplicationContext(), ack); } catch (Exception e) { Log.e(MCMNotificationModule.TAG,"PendingAcksDeliveryService: Error sending pending ack ("+e.getMessage()+")",e); } } } private void sendToMalcom(String ackData) throws Exception{ String theJSON = ackData; Log.d(MCMNotificationModule.TAG, "PendingAcksDeliveryService: "+theJSON); URL url = null; try { String malcomDate = HttpDateUtils.formatDate(new Date()); url = new URL(MCMCoreAdapter.getInstance().coreGetProperty(MCMCoreAdapter.PROPERTIES_MALCOM_BASEURL) + MCMNotificationModule.notification_ack); // Prepare required data for headers, these headers are requested by Malcom beacon API. String headers = "x-mcm-date:" + malcomDate+"\n"; String md5 = ToolBox.md5_calculateMD5(theJSON); String password = ToolBox.deliveries_getDataToSign(headers, "application/json", "", "POST", MCMNotificationModule.notification_ack, md5); password = DigestUtils.calculateRFC2104HMAC(password, MCMCoreAdapter.PROPERTIES_MALCOM_APPSECRETKEY); Map<String, String> headersData = new HashMap<String, String>(); headersData.put("Authorization", "basic " + new String(Base64.encode(new String(MCMCoreAdapter.getInstance().coreGetProperty(MCMCoreAdapter.PROPERTIES_MALCOM_APPID) + ":" + password).getBytes()))); headersData.put("Content-Type", "application/json"); headersData.put("content-md5", md5); headersData.put("x-mcm-date", malcomDate); ToolBox.net_httpclient_doAction(HTTP_METHOD.POST, url.toString(), theJSON, headersData); } catch (Exception e) { Log.e(MCMNotificationModule.TAG, "PendingAcksDeliveryService: Error sending ack data to Malcom service url '"+url.toString()+"': "+e.getMessage(),e); throw e; } } }