package com.google.samplesolutions.mobileassistant; import java.io.IOException; import com.google.samplesolutions.mobileassistant.messageEndpoint.MessageEndpoint; import com.google.samplesolutions.mobileassistant.messageEndpoint.model.CollectionResponseMessageData; import com.google.samplesolutions.mobileassistant.messageEndpoint.model.MessageData; import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpRequestInitializer; import com.google.api.client.json.jackson.JacksonFactory; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.Button; import android.widget.TextView; /** * An activity that communicates with your App Engine backend via Cloud * Endpoints. * * When the user hits the "Register" button, a message is sent to the backend * (over endpoints) indicating that the device would like to receive broadcast * messages from it. Clicking "Register" also has the effect of registering this * device for Google Cloud Messaging (GCM). Whenever the backend wants to * broadcast a message, it does it via GCM, so that the device does not need to * keep polling the backend for messages. * * If you've generated an App Engine backend for an existing Android project, * this activity will not be hooked in to your main activity as yet. You can * easily do so by adding the following lines to your main activity: * * Intent intent = new Intent(this, RegisterActivity.class); * startActivity(intent); * * To make the sample run, you need to set your PROJECT_NUMBER in * GCMIntentService.java. If you're going to be running a local version of the * App Engine backend (using the DevAppServer), you'll need to toggle the * LOCAL_ANDROID_RUN flag in CloudEndpointUtils.java. See the javadoc in these * classes for more details. * * For a comprehensive walkthrough, check out the documentation at * http://developers.google.com/eclipse/docs/cloud_endpoints */ public class RegisterActivity extends Activity { enum State { REGISTERED, REGISTERING, UNREGISTERED, UNREGISTERING } private State curState = State.UNREGISTERED; private OnTouchListener registerListener = null; private OnTouchListener unregisterListener = null; private MessageEndpoint messageEndpoint = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); Button regButton = (Button) findViewById(R.id.regButton); registerListener = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: if (GCMIntentService.PROJECT_NUMBER == null || GCMIntentService.PROJECT_NUMBER.length() == 0) { showDialog("Unable to register for Google Cloud Messaging. " + "Your application's PROJECT_NUMBER field is unset! You can change " + "it in GCMIntentService.java"); } else { updateState(State.REGISTERING); try { GCMIntentService.register(getApplicationContext()); } catch (Exception e) { Log.e(RegisterActivity.class.getName(), "Exception received when attempting to register for Google Cloud " + "Messaging. Perhaps you need to set your virtual device's " + " target to Google APIs? " + "See https://developers.google.com/eclipse/docs/cloud_endpoints_android" + " for more information.", e); showDialog("There was a problem when attempting to register for " + "Google Cloud Messaging. If you're running in the emulator, " + "is the target of your virtual device set to 'Google APIs?' " + "See the Android log for more details."); updateState(State.UNREGISTERED); } } return true; case MotionEvent.ACTION_UP: return true; default: return false; } } }; unregisterListener = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: updateState(State.UNREGISTERING); GCMIntentService.unregister(getApplicationContext()); return true; case MotionEvent.ACTION_UP: return true; default: return false; } } }; regButton.setOnTouchListener(registerListener); /* * build the messaging endpoint so we can access old messages via an endpoint call */ MessageEndpoint.Builder endpointBuilder = new MessageEndpoint.Builder( AndroidHttp.newCompatibleTransport(), new JacksonFactory(), new HttpRequestInitializer() { public void initialize(HttpRequest httpRequest) { } }); messageEndpoint = CloudEndpointUtils.updateBuilder(endpointBuilder).build(); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); /* * If we are dealing with an intent generated by the GCMIntentService * class, then display the provided message. */ if (intent.getBooleanExtra("gcmIntentServiceMessage", false)) { showDialog(intent.getStringExtra("message")); if (intent.getBooleanExtra("registrationMessage", false)) { if (intent.getBooleanExtra("error", false)) { /* * If we get a registration/unregistration-related error, * and we're in the process of registering, then we move * back to the unregistered state. If we're in the process * of unregistering, then we move back to the registered * state. */ if (curState == State.REGISTERING) { updateState(State.UNREGISTERED); } else { updateState(State.REGISTERED); } } else { /* * If we get a registration/unregistration-related success, * and we're in the process of registering, then we move to * the registered state. If we're in the process of * unregistering, the we move back to the unregistered * state. */ if (curState == State.REGISTERING) { updateState(State.REGISTERED); } else { updateState(State.UNREGISTERED); } } } else { /* * if we didn't get a registration/unregistration message then * go get the last 5 messages from app-engine */ new QueryMessagesTask(this, messageEndpoint).execute(); } } } private void updateState(State newState) { Button registerButton = (Button) findViewById(R.id.regButton); switch (newState) { case REGISTERED: registerButton.setText("Unregister"); registerButton.setOnTouchListener(unregisterListener); registerButton.setEnabled(true); break; case REGISTERING: registerButton.setText("Registering..."); registerButton.setEnabled(false); break; case UNREGISTERED: registerButton.setText("Register"); registerButton.setOnTouchListener(registerListener); registerButton.setEnabled(true); break; case UNREGISTERING: registerButton.setText("Unregistering..."); registerButton.setEnabled(false); break; } curState = newState; } private void showDialog(String message) { new AlertDialog.Builder(this) .setMessage(message) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); } }).show(); } /* * Need to run this in background so we don't hold up the UI thread, * this task will ask the App Engine backend for the last 5 messages * sent to it */ private class QueryMessagesTask extends AsyncTask<Void, Void, CollectionResponseMessageData> { Exception exceptionThrown = null; Activity activity; MessageEndpoint messageEndpoint; public QueryMessagesTask(Activity activity, MessageEndpoint messageEndpoint) { this.activity = activity; this.messageEndpoint = messageEndpoint; } @Override protected CollectionResponseMessageData doInBackground(Void... params) { try { CollectionResponseMessageData messages = messageEndpoint.listMessages().setLimit(5).execute(); return messages; } catch (IOException e) { exceptionThrown = e; return null; //Handle exception in PostExecute } } protected void onPostExecute(CollectionResponseMessageData messages) { // Check if exception was thrown if (exceptionThrown != null) { Log.e(RegisterActivity.class.getName(), "Exception when listing Messages", exceptionThrown); showDialog("Failed to retrieve the last 5 messages from " + "the endpoint at " + messageEndpoint.getBaseUrl() + ", check log for details"); } else { TextView messageView = (TextView) findViewById(R.id.msgView); messageView.setText("Last 5 Messages read from " + messageEndpoint.getBaseUrl() + ":\n"); for(MessageData message : messages.getItems()) { messageView.append(message.getMessage() + "\n"); } } } } }