Android Open Source - Android-SDK Cloud Push Service






From Project

Back to project page Android-SDK.

License

The source code is released under:

MIT License

If you think the Android project Android-SDK listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package net.getcloudengine;
//from   w w  w  .  j  av a  2  s . c  o m
import io.socket.IOAcknowledge;
import io.socket.IOCallback;
import io.socket.SocketIO;
import io.socket.SocketIOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.Message;
import android.util.Log;



public class CloudPushService extends Service {
    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;
    private static final String TAG = "CloudPushService";
    private int maxAttempts = 3;
    private final static String pushCallbackFilename = "PushCallback.ser";
    private final static String activityFilename = "Activity.ser";
    
    private int attemptInterval = 60000;    // Around the same as heartbeat timeout of the server
    private static PushCallback callback = new PushCallback();  //Default push callback handler
    private static HashMap<String, SocketIO> subscriptions = new HashMap<String, SocketIO>();
    private STATE state = STATE.DISCONNECTED;
    
    private enum STATE {
      CONNECTED,
      CONNECTION_IN_PROGRESS,
      DISCONNECTED
      
    };
    
    /**
     * This method allows you to define which activity of
     * the app will be invoked when the user clicks the
     * notification message 
     * 
     * @param context The application's context
       *            
       * @param activity The Class of the activity that needs to be 
       *   invoked
       * 
     * @throws CloudException If invalid parameters are passed 
       * 
       */
    public static void setActivity(Context context, Class<? extends Activity> activity){
      
      if(activity == null){
        throw new CloudException("Invalid activity class");
      }
      
      callback.setActivity(activity);
      
      File file = new File(context.getFilesDir(), activityFilename);
      
      if(file.exists()){
        // Avoid writing to the file every time the app
        // is opened.
        return;
      }
      
    
      try
        {
           FileOutputStream fileOut =
               context.openFileOutput(activityFilename, Context.MODE_PRIVATE);
           ObjectOutputStream out = new ObjectOutputStream(fileOut);
           out.writeObject(activity);
           out.close();
           fileOut.close();  
        }catch(IOException e)
        {
            e.printStackTrace();
        }
        
    }
    
    /**
     * This method allows you to install a custom callback function
     * that will be invoked when the user clicks a notification
     * message. 
     * 
     * @param context The application's context
       *            
       * @param cbk The callback object which needs to be installed. The object
       * must be a subclass of net.getcloudengine.PushCallback. You may 
       * extend or override the default handler function of the PushCallback
       * object by defining handleMessage method of the object. The default 
       * handleMessage method only displays the notification in the notification area
       * when a message is received. The PushCallback object provided must satisfy 
       * certain restrictions - 
       * 1. The object must be serializable i.e. it should implement java.io.Serializable interface
       * 2. The handleMessage method does not run in the UI thread
       * 3. It is recommended to keep the handleMessage function as short as possible. 
       * If you need to do blocking I/O such as networking activities, 
       * it is recommended to spawn a separate thread for that purpose. 
       * 4. If you're declaring the handler class inside an Activity or a container class, 
       * please declare the class as static in order to make it Serializable
       * 
     * @throws CloudException If invalid parameters are passed 
       * 
       */
    public static void installCallback(Context context, PushCallback cbk){
      
      if(context == null || cbk == null){
        throw new CloudException("Invalid parameters provided");
      }
      
      File file = new File(context.getFilesDir(), pushCallbackFilename);
      if(file.exists())
      {
        // Avoid writing to the file every time the app
          // is opened.
          return;
      }
      
      callback = cbk;
      // Save custom callback to disc
        try{
             FileOutputStream fileOut =
                 context.openFileOutput(pushCallbackFilename, Context.MODE_PRIVATE);
             
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(CloudPushService.callback);
             out.close();
             fileOut.close();  
          }catch(IOException e)
          {
              e.printStackTrace();
          }
       
    }
    
    private SocketIO socket_call(String app_id)
    {
        String apiKey = CloudEngine.getApiKey();
        String appId = CloudEngine.getAppId();
        final Context context = getApplicationContext();
        if(apiKey == null || apiKey == "" || appId == null || appId == "")
          return null;
        
        try {
          
          String host = CloudEndPoints.socketServer;
          SocketIO socket = new SocketIO();
          subscriptions.put(app_id, socket);
          socket.addHeader("Authorization", "Token " + apiKey);
          socket.addHeader("AppId", appId);
          socket.connect(host, new IOCallback(){ 

                @Override
                public void on(String event, IOAcknowledge ack, Object... args) {
                  if ("push".equals(event) && args.length > 0)
                  {
                    String msg = (String) args[0];
                    callback.handleMessage(context, msg);
                    
                  }            
                }

                @Override
                public void onConnect() {
                  
                  Log.d(TAG, "Push service connected to server");
                  state = STATE.CONNECTED;
                }

                @Override
                public void onDisconnect() {
                  
                  Log.d(TAG, "Push service disconnected");
                  state = STATE.DISCONNECTED;
                }

                @Override
                public void onError(SocketIOException exception) {
                  
                  String msg = exception.getMessage();
                  Log.e(TAG, "Error in connecting. " + msg);
                  state = STATE.DISCONNECTED;
                }

                @Override
                public void onMessage(String arg0, IOAcknowledge arg1) {
                  
                }

                @Override
                public void onMessage(JSONObject arg0, IOAcknowledge arg1) {
                  
                  
                }
                
              });
            return socket;
          
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }
        
        return null;
      }

    // Handler that receives messages from the thread
    private final class ServiceHandler extends Handler {
        
      public ServiceHandler(Looper looper) {
            super(looper);
        }
      
        @Override
        public void handleMessage(Message msg) {
          SocketIO socket = null;
          Bundle data = msg.getData();
          String app_id = data.getString("AppId");
          int attempts = 0;
          while(attempts < maxAttempts)
          {
           socket  = socket_call(app_id);
          
             //Wait for either socket to be connected
           if(state != STATE.CONNECTED)
           {
            try {
              Thread.sleep(attemptInterval);  
            } catch (InterruptedException e) {
            }
           }
          
           // Still not connected?
          if(state != STATE.CONNECTED){
          attempts += 1;
          continue;    // try again
        }
           else{
             break;
           }
           
          }
          
          if(state != STATE.CONNECTED){
            
            // If state is left in STATE.CONNECTION_IN_PROGRESS,
            // further attempts to connect will be blocked.
            state = STATE.DISCONNECTED;
            Log.e(TAG, "Socket not connected. Giving up...");
          }
        
        }
    }

    @Override
    public void onCreate() {
      
      HandlerThread thread = new HandlerThread("ServiceStartArguments",
              Process.THREAD_PRIORITY_BACKGROUND);
      thread.start();
      
      // Get the HandlerThread's Looper and use it for our Handler 
      mServiceLooper = thread.getLooper();
      mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        
      String appId = null;
      Bundle data = new Bundle();
      boolean connect = true;
      //Read app id from disc
      SharedPreferences sharedPref = getApplicationContext().getSharedPreferences(
      CloudEngine.PREFERENCE_FILE , Context.MODE_PRIVATE);
      appId = sharedPref.getString(CloudEngine.APP_ID, null);
      
      if (appId != null) {
        
          //Check if we are already subscribed to this channel
         if(subscriptions.containsKey(appId))
         {      
           SocketIO socket = subscriptions.get(appId);
           if( socket != null && socket.isConnected()){
             connect = false;
             Log.d(TAG, "Already subscribed. Not connecting push service");
           }
         }
         
         if(connect){
           
           
           manageCustomCallback();
           installActivity();
           // Start the service if no connection is in progress
           if( state == STATE.DISCONNECTED )
           {
             Log.d(TAG, "Attempting new socketio connection");
             Message msg = mServiceHandler.obtainMessage();
                data.putString("AppId", appId);
                msg.setData(data);
                mServiceHandler.sendMessage(msg);
                state = STATE.CONNECTION_IN_PROGRESS;
           }       
           
         }
         
       }else{
         Log.e(TAG, "Push service didn't find app id.");
       }
        return START_STICKY;
    }
    
    private void installActivity(){
      
    // check if we need to install custom handler
       File file = new File(getFilesDir(), activityFilename);
       if(file.exists())
       {
         FileInputStream fileIn = null;
         ObjectInputStream inputStream = null;
        try {
          fileIn = new FileInputStream(file.getAbsolutePath());
          inputStream = new ObjectInputStream(fileIn);
          Class<? extends Activity> activity = (Class<? extends Activity>) inputStream.readObject();
          setActivity( getApplicationContext(), activity);
          
        } catch (Exception e) {
          e.printStackTrace();
        }
        finally{
          
            try{
              if(inputStream != null)
                inputStream.close();
              
              if(fileIn != null)
                fileIn.close();
            }
            catch(Exception e){
            }
        }
       }
      
    }

    private void manageCustomCallback(){
      
    // check if we need to install custom handler
       File file = new File(getFilesDir(), pushCallbackFilename);
       if(file.exists())
       {
          FileInputStream fileIn = null;
         ObjectInputStream inputStream = null;
        try {
          fileIn = new FileInputStream(file.getAbsolutePath());
          inputStream = new ObjectInputStream(fileIn);
          CloudPushService.callback = (PushCallback) inputStream.readObject();
          
        } catch (Exception e) {
          e.printStackTrace();
        }
        finally{
          
            try{
              if(inputStream != null)
                inputStream.close();
              
              if(fileIn != null)
                fileIn.close();
            }
            catch(Exception e){
            }
        }
       }
    }
    
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    @Override
    public void onDestroy() { 
      
    }
}




Java Source Code List

net.getcloudengine.CloudAuthException.java
net.getcloudengine.CloudEndPoints.java
net.getcloudengine.CloudEngineReceiver.java
net.getcloudengine.CloudEngineSdkVersion.java
net.getcloudengine.CloudEngineUtils.java
net.getcloudengine.CloudEngine.java
net.getcloudengine.CloudException.java
net.getcloudengine.CloudFile.java
net.getcloudengine.CloudObjectException.java
net.getcloudengine.CloudObject.java
net.getcloudengine.CloudPushService.java
net.getcloudengine.CloudQuery.java
net.getcloudengine.CloudUser.java
net.getcloudengine.DeleteObjectCallback.java
net.getcloudengine.FetchFileCallback.java
net.getcloudengine.FetchObjectCallback.java
net.getcloudengine.FindObjectsCallback.java
net.getcloudengine.GetObjectCallback.java
net.getcloudengine.LoginCallback.java
net.getcloudengine.LogoutCallback.java
net.getcloudengine.PasswordResetCallback.java
net.getcloudengine.PushCallback.java
net.getcloudengine.SaveFileCallback.java
net.getcloudengine.SaveObjectCallback.java
net.getcloudengine.SignupCallback.java