You are here

Extending the GUI

This task describes how to extend the basic GUI for your site code.
This task assumes you have already completed the previous task. In this task you will simply modify the code you created and tested in the previous task.

In this task you will learn how to add buttons to your user interface to allow the user to join and leave sites, also you will add buttons to allow sites to be added to favorites (or removed) and also to cancel any pending requests to moderated sites. When an operation is carried out, a toast indicates the nature of the change.

  1. MainActivity needs to be changed to allow the passing of the siteService object to the SiteDetailActivity. The siteService object is Parcelable, so this needs to be taken into account when unpacking it. Modify your MainActivity as follows:

                
    package com.alfresco.tutorials.sitetest;
    
    import java.util.ArrayList;
    
    import org.alfresco.mobile.android.api.exceptions.AlfrescoSessionException;
    import org.alfresco.mobile.android.api.model.Site;
    import org.alfresco.mobile.android.api.services.SiteService;
    import org.alfresco.mobile.android.api.session.RepositorySession;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.Toast;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.AdapterView;
    
    
    public class MainActivity extends Activity {
    		
    	private SiteArrayAdapter adapter;
    	private ArrayList<Site> sites;
    	private SiteService siteService;
    	private RepositorySession session;
    	
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_main);
    
            LinearLayout ll = (LinearLayout) findViewById(R.id.linearLayout);       
            ListView lv = new ListView(this);
            
            sites = new ArrayList<Site>();        
            adapter = new SiteArrayAdapter(this, sites);
            lv.setAdapter(adapter);
            ll.addView(lv);
            adapter.setNotifyOnChange(true);
                    
            lv.setOnItemClickListener(new OnItemClickListener() {
    
      		  @Override
            	  public void onItemClick(AdapterView<?> parent, View view,
            	    int position, long id) {
            		      	    
            		Intent intent = new Intent(getApplicationContext(), SiteDetailActivity.class);	
            		
            		Site site = sites.get(position);
            		      		
        			intent.putExtra("targetSite", site);
        			intent.putExtra("siteService", siteService);
            		startActivity(intent);
    
            	  }
            });
            
            
            // Modify to suit your SkyVault server installation 
            String url = "http://localhost:8080/alfresco";
            String username = "admin";
            String password = "admin";
    
            new ConnectToRepo().execute(url, username, password);
    
        }
        
    
        class ConnectToRepo extends AsyncTask<String, Integer, String> {
    
            private static final String TAG = "ConnectToRepo";
            
            @Override
            protected String doInBackground(String... params) {
    
                Log.d(TAG, "doInBackground");
                Log.d(TAG, params[0] + ":" + params[1] + ":" + params[2]);
    
                String url = params[0];
                String username = params[1];
                String password = params[2];
    
                try {
                    // connect to on-premise repo
                   session = RepositorySession.connect(url,
                            username, password);
    
                        // Get site service
                        siteService = session.getServiceRegistry()
                                .getSiteService();
    
                        // Get all sites
                        sites = (ArrayList<Site>) siteService.getAllSites();
    
    
                        
                } catch (AlfrescoSessionException e) {
                	Log.e(TAG, "Failed to connect: " + e.toString()); 
                	System.exit(0);
                }
    
                Log.d(TAG, "doInBackground Complete");
                return "doInBackground Complete";
            }
    
            @Override
            protected void onPostExecute(String result) {
                super.onPostExecute(result);
                Log.d(TAG, "onPostExecute");
                Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();
            	adapter.addSites((ArrayList<Site>) sites);
            	adapter.notifyDataSetChanged();
            }
    
        }
    
    }                          
                
              

    The main change here is to pull out the siteService object as a private variable (so it can be accessed outside of the code where it is initialized), and is then packaged into an intent, which will be sent to SiteDetailActivity.

    Note: As always you will need to change the URL, username and password to suit your SkyVault installation.
  2. The SiteDetailActivity also needs to be changed. Modify your code as follows:

                
    package com.alfresco.tutorials.sitetest;
    
    import java.util.List;
    
    import org.alfresco.mobile.android.api.exceptions.AlfrescoServiceException;
    import org.alfresco.mobile.android.api.model.Site;
    import org.alfresco.mobile.android.api.services.SiteService;
    
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Intent;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TableLayout;
    import android.widget.TextView;
    import android.widget.Toast;
    import android.support.v4.app.NavUtils;
    
    public class SiteDetailActivity extends Activity {
    
    	private static final String TAG = "SiteDetailActivity";
    
    	private static final int NOP = 0;
    	private static final int JOIN = 100;
    	private static final int JOIN_REQUEST = 101;
    	private static final int LEAVE = 102;
    	private static final int CANCEL = 103;
    	private static final int ADD_FAVE = 104;
    	private static final int REMOVE_FAVE = 105;
    
    	private Site site;
    	private SiteService siteService;
    
    	private int operation = NOP;
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_site_detail);
    		// Show the Up button in the action bar.
    		getActionBar().setDisplayHomeAsUpEnabled(true);
    
    		// Get message from intent
    		Intent intent = getIntent();
    		site = (Site) intent.getSerializableExtra("targetSite");
    		siteService = (SiteService) intent.getParcelableExtra("siteService");
    
    		// We now need to display site details in a UI
    
    		TextView tv = (TextView) findViewById(R.id.site_short_name_value);
    		tv.setText((CharSequence) site.getShortName());
    
    		tv = (TextView) findViewById(R.id.site_description_value);
    		tv.setText((CharSequence) site.getDescription());
    
    		tv = (TextView) findViewById(R.id.site_identifier_value);
    		tv.setText((CharSequence) site.getIdentifier());
    
    		tv = (TextView) findViewById(R.id.site_GUID_value);
    		tv.setText((CharSequence) site.getGUID());
    
    		tv = (TextView) findViewById(R.id.site_title_value);
    		tv.setText((CharSequence) site.getTitle());
    
    		tv = (TextView) findViewById(R.id.site_visibility_value);
    
    		tv.setText((CharSequence) site.getVisibility().value());
    
    		// isFavorite
    		if (site.isFavorite()) {
    			tv = (TextView) findViewById(R.id.site_is_favorite_value);
    			tv.setText("True");
    		} else {
    			tv = (TextView) findViewById(R.id.site_is_favorite_value);
    			tv.setText("False");
    		}
    
    		// isMember
    		if (site.isMember()) {
    			tv = (TextView) findViewById(R.id.site_is_member_value);
    			tv.setText("True");
    		} else {
    			tv = (TextView) findViewById(R.id.site_is_member_value);
    			tv.setText("False");
    		}
    
    		// isPendingMember
    		if (site.isPendingMember()) {
    			tv = (TextView) findViewById(R.id.site_is_pending_member_value);
    			tv.setText("True");
    		} else {
    			tv = (TextView) findViewById(R.id.site_is_pending_member_value);
    			tv.setText("False");
    		}
    
    		drawButtons();
    
    	}
    
    	public void drawButtons() {
    
    		String visibility = site.getVisibility().value();
    		boolean isMember = site.isMember();
    		boolean isPendingMember = site.isPendingMember();
    		boolean isFavorite = site.isFavorite();
    
    		Log.d(TAG, "DRAW_BUTTONS...");
    
    		// if public and not member draw Join
    		if (visibility.equalsIgnoreCase("PUBLIC") && !isMember) {
    
    			Log.d(TAG, "DRAW_BUTTONS: draw Join button");
    			Button btn = new Button(this);
    			btn.setText("Join");
    			TableLayout layout = (TableLayout) findViewById(R.id.tableLayout);
    			layout.addView(btn);
    			btn.setId(JOIN);
    			btn.setOnClickListener(buttonListener);
    		}
    
    		// if member draw Leave
    		if (isMember) {
    
    			Log.d(TAG, "DRAW_BUTTONS: draw Leave button");
    			Button btn = new Button(this);
    			btn.setText("Leave");
    			TableLayout layout = (TableLayout) findViewById(R.id.tableLayout);
    			layout.addView(btn);
    			btn.setId(LEAVE);
    			btn.setOnClickListener(buttonListener);
    		}
    
    		// if moderated and not member draw Join Request, but not if request pending
    		if (visibility.equalsIgnoreCase("MODERATED") && !isMember && !isPendingMember) {
    
    			Log.d(TAG, "DRAW_BUTTONS: draw Join Request button");
    			Button btn = new Button(this);
    			btn.setText("Join Request");
    			TableLayout layout = (TableLayout) findViewById(R.id.tableLayout);
    			layout.addView(btn);
    			btn.setId(JOIN_REQUEST);
    			btn.setOnClickListener(buttonListener);
    		}
    
    		// if member and not favorite draw Add to favorites
    		if (isMember && !isFavorite) {
    
    			Log.d(TAG, "DRAW_BUTTONS: draw Add to favorites button");
    			Button btn = new Button(this);
    			btn.setText("Add to Favorites");
    			TableLayout layout = (TableLayout) findViewById(R.id.tableLayout);
    			layout.addView(btn);
    			btn.setId(ADD_FAVE);
    			btn.setOnClickListener(buttonListener);
    		}
    
    		// if join request pending draw Cancel join request
    		if (isPendingMember) {
    
    			Log.d(TAG, "DRAW_BUTTONS: draw Cancel join request button");
    			Button btn = new Button(this);
    			btn.setText("Cancel Join Request");
    			TableLayout layout = (TableLayout) findViewById(R.id.tableLayout);
    			layout.addView(btn);
    			btn.setId(CANCEL);
    			btn.setOnClickListener(buttonListener);
    		}
    
    		// if favorite draw remove from favorites
    		if (isFavorite) {
    
    			Log.d(TAG, "DRAW_BUTTONS: draw Remove from favorites button");
    			Button btn = new Button(this);
    			btn.setText("Remove from Favorites");
    			TableLayout layout = (TableLayout) findViewById(R.id.tableLayout);
    			layout.addView(btn);
    			btn.setId(REMOVE_FAVE);
    			btn.setOnClickListener(buttonListener);
    		}
    
    	}
    
    	private OnClickListener buttonListener = new OnClickListener() {
    
    		@Override
    		public void onClick(View v) {
    
    			operation = v.getId();
    			
    			// p1 and p2 for future use. Operation is passed but not used.
    			new SubmitSiteOperation().execute(String.valueOf(operation), "p1", "p2");
    
    		}
    	};
    
    	@Override
    	public boolean onCreateOptionsMenu(Menu menu) {
    		// Inflate the menu; this adds items to the action bar if it is present.
    		getMenuInflater().inflate(R.menu.activity_site_detail, menu);
    		return true;
    	}
    
    	@Override
    	public boolean onOptionsItemSelected(MenuItem item) {
    		switch (item.getItemId()) {
    		case android.R.id.home:
    			// This ID represents the Home or Up button. In the case of this
    			// activity, the Up button is shown. Use NavUtils to allow users
    			// to navigate up one level in the application structure. For
    			// more details, see the Navigation pattern on Android Design:
    			//
    			// http://developer.android.com/design/patterns/navigation.html#up-vs-back
    			//
    			NavUtils.navigateUpFromSameTask(this);
    			return true;
    		}
    		return super.onOptionsItemSelected(item);
    	}
    
    	class SubmitSiteOperation extends AsyncTask<String, Integer, String> {
    
    		private static final String TAG = "SubmitSiteOperations";
    		
    		private String message;
    
    		@Override
    		protected String doInBackground(String... params) {
    
    			Log.d(TAG, "doInBackground");
    			Log.d(TAG, params[0] + ":" + params[1] + ":" + params[2]);
    
    			try {
    
    				switch (operation) {
    
    				case JOIN:
    					site = siteService.joinSite(site);
    					message = "You joined site "+site.getShortName();
    					break;
    
    				case LEAVE:
    					site = siteService.leaveSite(site);
    					message = "You left site "+site.getShortName();
    					break;
    
    				case JOIN_REQUEST:
    					site = siteService.joinSite(site);
    					message = "Request queued for site "+site.getShortName();
    					break;
    
    				case ADD_FAVE:
    					site = siteService.addFavoriteSite(site);
    					message = site.getShortName()+" added to your favorites";
    					break;
    
    				case CANCEL:
    					// get pending site requests
    					// and cancel where shortName matches
    					List<Site> requests = siteService
    							.getPendingSites();
    					for (Site request : requests) {
    						if (request.getShortName().equals(
    								site.getShortName())) {
    							site = siteService.cancelRequestToJoinSite(request);
    						}
    					}
    					message = "Requests cancelled for "+site.getShortName();
    					break;
    
    				case REMOVE_FAVE:
    					site = siteService.removeFavoriteSite(site);
    					message = site.getShortName()+" removed from your favorites";
    					break;
    
    				case NOP:
    					message = "Nothing useful!";
    					break;
    				}
    
    			} catch (AlfrescoServiceException e) {
    				Log.e(TAG,
    						"Error while working with site: " + site.getShortName());
    				Log.e(TAG, "Exception generated: " + e.toString());
    				Log.e(TAG, "With Error Code: " + e.getErrorCode());
    
    				System.exit(0);
    			}
    
    			Log.d(TAG, "Operation Complete: " + operation + " "+message);
    			return message;
    		}
    
    		@Override
    		protected void onPostExecute(String result) {
    			super.onPostExecute(result);
    			Log.d(TAG, "onPostExecute");
    			Toast.makeText(SiteDetailActivity.this, result, Toast.LENGTH_LONG)
    					.show();
    		}
    
    	}
    
    }            
    
    
              

    There are a number of additions here over the previous code. First, constants for the various site operations that can be handled are defined. Also a variable to store the unpacked siteService object is declared. Note that siteService is a parcelable object, so is unpacked with a different method call to serializable objects.

    Code to dynamically draw the relevant buttons, depending on the site status, is located in drawButtons(). This method determines what the relevant buttons to draw are, and then dynamically creates them and adds them to the user interface. Once the user clicks the button to perform the operation they want, the button id is recorded and this is used to set the required operation.

    As network operations, such as requesting to join a site, cannot be carried out in the main UI thread in Android, these site operations (join, leave, and so on) are moved to an Async task. The switch statement routes the operation request to the correct code.

    The onPostExecute() code simply displays a toast providing some feedback to the user that the required operation has been carried out.

  3. You are now ready to run your application. You will be presented with a list of sites. Click on a site will show you relevant buttons depending on your membership status, as shown in the following screenshot:

  4. Play with the application thoroughly to make sure it works as you expect. Feel free to create more test sites in Share.