public class CreateUpdateShopResponse {
	@Expose
	public String submissionId;
	@Expose
	public String helperId;
	@Expose
	public int responseId;
} public class CreateUpdateShopResponseType implements Serializable {
	private static final long serialVersionUID = 1L;
	@Expose
	public int id;
	@Expose
	public String message;
	@Expose
	public boolean isReject;
	@Expose
	public boolean isSeriousReject;
	@Expose
	public boolean isAccept;
} public class CreateShopSubmission implements Serializable {
	private static final long serialVersionUID = 1L;
	

	
	@Expose
	public String id;
	@Expose
	public String helperId;
	@Expose
	public String name;
	@Expose
	public String shortDescription;
	@Expose
	public String fullDescription;
	@Expose
	public String searchTags;
	
	@Expose
	public String shopType;
	@Expose
	public String openHours;
	@Expose
	public int district;
	@Expose
	public String address;
	@Expose
	public String phone;
	@Expose
	public int latitude1000000; /* the value of latitude * 1000000, the Accuracy is ~0.1m */
	@Expose
	public int longitude1000000; /* the value of longitude * 1000000, the Accuracy is ~0.1m */
	@Expose
	public String photoUrl;
}
 public class GcmIntentService extends IntentService {
	public static final String GCM_AUTH_CODE = "authCode";
	
	public GcmIntentService() {
		super("GcmIntentService");
	}

	private void processAuthCode(String authCode) {
		// relay the message to activity
		Intent i = new Intent(GCM_AUTH_CODE).putExtra("authCode", authCode);
		LocalBroadcastManager.getInstance(this).sendBroadcast(i);
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		Bundle extras = intent.getExtras();
		GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
		// The getMessageType() intent parameter must be the intent you received
		// in your BroadcastReceiver.
		String messageType = gcm.getMessageType(intent);

		if (!extras.isEmpty()) { // has effect of unparcelling Bundle
			// no need to care other GCM message type
			if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
				Set<String> keys = extras.keySet();

				if (keys.contains("data") == true)
				{
					//this project will have only one type of message, 
					//thus no need to determine the message type 
					processAuthCode(extras.getString("data"));
				}
			}
		}
		// Release the wake lock provided by the WakefulBroadcastReceiver.
		GcmBroadcastReceiver.completeWakefulIntent(intent);
	}


} public class CreateShopSubmissionOutput implements Serializable {
	private static final long serialVersionUID = 1L;
	
	@Expose
	public CreateShopSubmission s;
	@Expose
	public boolean isCreator;
	@Expose
	public boolean isReviewer;
}
 public interface AuthCodeRequester {
	public void onSendAuthCodeRequestError(int errorCode);
} public class AuthCodeUtil {	
    public static void sendAuthCodeRequest(final AuthCodeRequester receiver, String regId)
    {
    	Response.Listener<String> listener = new Response.Listener<String>() {
			@Override
			public void onResponse(String response) {
				try {
					Dummy dummy = Config.defaultGSON.fromJson(response, Dummy.class);
					dummy.checkValid();
				} catch (Exception ex) {
					receiver.onSendAuthCodeRequestError(Config.WIFI_ERROR);
				}
			}
		};

		Response.ErrorListener errorListener = new Response.ErrorListener() {
			@Override
			public void onErrorResponse(VolleyError error) {
				if ((error instanceof NetworkError) || (error instanceof NoConnectionError) || (error instanceof TimeoutError)) {
					receiver.onSendAuthCodeRequestError(Config.NETWORK_ERROR);
				}
				else
					receiver.onSendAuthCodeRequestError(Config.OTHERS_ERROR);
			}
		};

		String url = "";
		try {
			url = Config.HOST_URL + "/AuthCode?deviceType=" + Config.deviceType
					+ "&regId=" + URLEncoder.encode(regId, "UTF-8")
					+ "&dt=" + URLEncoder.encode(Config.defaultDateTimeFormatter.print(DateTime.now()), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			// should never reach this line
			e.printStackTrace();
		}
		StringRequest request = new StringRequest(Request.Method.POST, url, listener, errorListener);
		request.setRetryPolicy(new DefaultRetryPolicy(Config.DEFAULT_HTTP_TIMEOUT, Config.DEFAULT_HTTP_MAX_RETRY, 1.5f));
		RequestManager.getInstance().getRequestQueue().add(request);
    }

} public class Config {	
	//some enum about network
	public static int WIFI_ERROR = 0;
	public static int NETWORK_ERROR = 1;
	public static int OTHERS_ERROR = 2;
	
	public static int NAME_MAX_LENGTH = 20;
	public static int SHORT_DESCRIPTION_MAX_LENGTH = 30;
	public static int FULL_DESCRIPTION_MAX_LENGTH = 200;
	public static int OPEN_HOURS_MAX_LENGTH = 100;
	public static int SEARCH_TAGS_MAX_LENGTH = 200;
	public static int ADDRESS_MAX_LENGTH = 150;
	public static int PHONE_MAX_LENGTH = 10;
	
	public final static String licenseUrl = "http://www.gnu.org/licenses/gpl-3.0.txt";
	public final static String[] shopTypes = new String[]{"食肆", "零售（食物）","零售（其他）", "服務"}; 
	public final static String deviceType  = "google-android"; 
	
	public final static int DEFAULT_SEARCH_RANGE = 100;
	
	public final static int WHOLE_HK = 0;
	public final static int HK_ISLAND = 1;
	public final static int KOWL0ON = 2;	
	public final static int NEW_TERRITORIES = 3;
	
	public final static int HK_NORTH_LAT1000000 = 22562222;
	public final static int HK_SOUTH_LAT1000000 = 22153889;
	public final static int HK_EAST_LNG1000000 = 114441667;
	public final static int HK_WEST_LNG1000000 = 113835278;
	
	//REMARKS: this is development purpose ID, and URL
	public static final String GCM_SENDER_ID = "458074465130";
	public static final String HOST_URL = "http://supportsmallshop1.marspotato.com//supportsmallshop";
	//public static final String HOST_URL = "http://supportsmallshop.marspotato.com/supportsmallshop";
	
	//the default http timeout
	public static final int DEFAULT_HTTP_TIMEOUT = 10000;//10000ms = 10 seconds
	
	//after the initial fail, the number of retry of http call
	public static final int DEFAULT_HTTP_MAX_RETRY = 1;
	
	//max number of image to be cached in disk
	public static final int MAX_DISK_CACHE_IMAGE = 100;
	
	public static DateTimeFormatter defaultDisplayDateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd");

	public static DateTimeFormatter defaultDateTimeFormatter = ISODateTimeFormat.basicDateTimeNoMillis();
	
	public static Gson defaultGSON = new GsonBuilder().registerTypeAdapter(DateTime.class, new DateTimeTypeConverter()).setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
	
	//time for a button to be disabled to avoid double action
	public static final int AVOID_DOUBLE_CLICK_PERIOD = 500;//500ms
	
	//THE time(in ms) that the progress bar will be delayed to show
	public static final int MS_GAME_PROGRESS_BAR_DELAY = 500; 
	
}
 public class ImageUtil {

	public static boolean isSw600dp()
	{
		//density * dp = pixel
		//dp = pixel / density
		double dpWidth = Resources.getSystem().getDisplayMetrics().widthPixels / Resources.getSystem().getDisplayMetrics().density;
		return dpWidth > 600;
	}
	
} public class MiscUtil {

	public static String getDistrictName(Activity a, int districtId)
	{
		String output = null;
		if (districtId == Config.WHOLE_HK)
			output = a.getString(R.string.whole_city);
		if (districtId == Config.HK_ISLAND )
			output = a.getString(R.string.hk_island);
		if (districtId == Config.KOWL0ON)
			output = a.getString(R.string.kowloon);
		if (districtId == Config.NEW_TERRITORIES)
			output = a.getString(R.string.new_territories);
		return output;
	}
	public static String getLatLngString(int value)
	{
		if (value == 0)
			return "/";
		int t1 = value / 1000000, t2 = value % 1000000;
		return "" + t1 + "." + String.format("%06d", t2);
	}
} public class RequestManager {

    private static RequestManager instance;
    private RequestQueue mRequestQueue;


    private RequestManager(Context context) {
    	mRequestQueue = Volley.newRequestQueue(context.getApplicationContext());
    }
    public RequestQueue getRequestQueue()
    {
    	return mRequestQueue;
    }

    // This method should be called first to do singleton initialization
    public static synchronized RequestManager getInstance(Context context) {
        if (instance == null) {
            instance = new RequestManager(context);
        }
        return instance;
    }

    public static synchronized RequestManager getInstance() {
        if (instance == null) {
            throw new IllegalStateException(RequestManager.class.getSimpleName() +
                    " is not initialized, call getInstance(..) method first.");
        }
        return instance;
    }
}
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Vector;
import org.joda.time.DateTime;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkError;
import com.android.volley.NoConnectionError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.TimeoutError;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.google.gson.JsonSyntaxException;
import com.marspotato.supportsmallshop.BO.CreateUpdateShopResponse;
import com.marspotato.supportsmallshop.BO.CreateUpdateShopResponseType;
import com.marspotato.supportsmallshop.BO.CreateShopSubmission;
import com.marspotato.supportsmallshop.gcm.GcmIntentService;
import com.marspotato.supportsmallshop.output.CreateShopSubmissionOutput;
import com.marspotato.supportsmallshop.util.AuthCodeRequester;
import com.marspotato.supportsmallshop.util.AuthCodeUtil;
import com.marspotato.supportsmallshop.util.Config;
import com.marspotato.supportsmallshop.util.ImageUtil;
import com.marspotato.supportsmallshop.util.MiscUtil;
import com.marspotato.supportsmallshop.util.RequestManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.Toast;

package com.marspotato.supportsmallshop;





public class ReviewCreateShopActivity extends Activity implements AuthCodeRequester {
	private BroadcastReceiver authCodeIntentReceiver;
	
	private CreateShopSubmissionOutput submissionOutput;
	private CreateUpdateShopResponseType[] responseTypes;
	private String regId;
	private String helperId;
	private CreateUpdateShopResponseType selectedResponse;
	

	
	private DateTime lastClickTime;//Just for avoiding double-click problem, no need to persistence
	
	@Override
	public void onSaveInstanceState(Bundle savedInstanceState) {
		super.onSaveInstanceState(savedInstanceState);
		savedInstanceState.putSerializable("submissionOutput", submissionOutput);
		savedInstanceState.putString("responseTypesJSON", Config.defaultGSON.toJson(responseTypes));
		savedInstanceState.putString("regId", regId);
		savedInstanceState.putString("helperId", helperId);
		savedInstanceState.putSerializable("selectedResponse", selectedResponse);
		
	}
	private void setupBlock(int fieldId, int blockId, String value)
	{
		if (value != null && value.isEmpty() == false )
		{
			findViewById(blockId).setVisibility(View.VISIBLE); 
			TextView field = (TextView) findViewById(fieldId);
			field.setText(value);
		}
		else
			findViewById(blockId).setVisibility(View.GONE); 
	}
	
	private void setupLocationIcon(int viewId, final int longitude1000000, final int latitude1000000)
	{
		ImageView locationIcon = (ImageView) findViewById(viewId);
		if (longitude1000000 == 0 && latitude1000000 == 0)
		{
			locationIcon.setVisibility(View.GONE);
			return;
		}
		locationIcon.setVisibility(View.VISIBLE);
		locationIcon.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if (lastClickTime != null && lastClickTime.plusMillis(Config.AVOID_DOUBLE_CLICK_PERIOD).isAfterNow())
					return;
				lastClickTime = DateTime.now();
				String uri = null;		
					uri = "http://maps.google.com/maps?q=loc:" + MiscUtil.getLatLngString(latitude1000000) + "," + MiscUtil.getLatLngString(longitude1000000);

				Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
				intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity");
				startActivity(intent);
			}
		});
	}
	private void displayData()
	{

		final CreateShopSubmission submission = submissionOutput.s;
