Android Open Source - GTHive G T Hive






From Project

Back to project page GTHive.

License

The source code is released under:

MIT License

If you think the Android project GTHive 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 com.craigsc.gthive;
//from w  ww .  j  a va  2s  .co m
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

/** 
 * Main class file for the application, handles loading and storing of login
 * credentials. Also contains the logic for connecting and authenticating to
 * the Georgia Tech LAWN wifi network.
 * @author Craig Campbell
 *
 */
public class GTHive extends Activity implements OnClickListener, TextWatcher {
  public static final String PREFS_NAME = "gthive_data";
  public static final int CLEARED_DATA = 3333;
  private static final String TAG = "GTHive";
  public static final String SSID = "GTWireless";
  private SharedPreferences settings;
  private SharedPreferences.Editor editor;
  private EditText user;
  private EditText pass;
  /** Whether any login info has changed since the screen was loaded */
  private boolean newText = false;
  private ProgressDialog dialog;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        user = (EditText)findViewById(R.id.username);
        pass = (EditText)findViewById(R.id.password);
        settings = getSharedPreferences(PREFS_NAME,0);
        editor = settings.edit();
        
        /* Set user/password textfields using stored info
         * if available, use "" if none is saved.
         */
        user.setText(settings.getString("user", ""));
        pass.setText(settings.getString("pass", ""));
        
        /* Hook up listeners */
        user.addTextChangedListener(this);
        pass.addTextChangedListener(this);
        ((Button)findViewById(R.id.login)).setOnClickListener(this);
    }

    /**
     * Button listener, validates the user/password text fields and
     * then proceeds with the authentication process by calling
     * {@link #checkWifi()}.
     */
  public void onClick(View v) {
    //set errors if user/password is blank
    if (pass.getText().toString().equals("") ||
        user.getText().toString().equals("")) {
      if (pass.getText().toString().equals("")) {
        pass.setError("Password is required");
        pass.requestFocus();
      }
      if (user.getText().toString().equals("")) {
        user.setError("Username is required");
        user.requestFocus();
      }
    }
    else {
      //clear errors, save new login info (if newText), and proceed.
      pass.setError(null);
      user.setError(null);
      if (newText && Prefs.getRememberLogin(this)) {
        editor.putString("user", user.getText().toString());
        editor.putString("pass", pass.getText().toString());
        editor.commit();
        newText = false;
      }
      checkWifi();
    }  
  }
  
  /**
   * The meat and potatoes of the program, this method spawns a new thread which
   * enables the wifi (if need be) and attempts to connect to a wifi network. Once connected,
   * it checks the ssid of the network to ensure it is 'GTwireless' and then proceeds to 
   * actually log the user in to the lawn network using the supplied username and password.
   * It also checks if ISS is enabled via the preferences and sends the appropriate param
   * if it is.
   * 
   * It is important to note that all of these network calls are happening on a separate thread
   * from the main UI thread so that the progress dialog proceeds smoothly. The two inner private
   * methods (updateDialog and display), however, run on the main UI thread since they deal with
   * changes made to the UI.
   */
  private void login() {
    final Context c = this;
    new Thread() {
      public void run() {
        WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
        ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
        
        //if wifi !enabled then attempt to enable
        if (!wifi.isWifiEnabled()) {
          if (!wifi.setWifiEnabled(true)) {
            display("Failed to enable wifi, ensure that your device is wifi enabled before trying again.");
            return;
          }
          updateDialog("Connecting to network...");
          int i = 0;
          
          //force a scan so connection occurs if wifi is setup properly in phone
          wifi.startScan();
          
          //if wifi is not connected to a network then check every second for 30 seconds for a connection
          while (!cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()) {
            if (i == 30) {
              display("Device timed out while attempting to connect to a wifi network. Please ensure that you have " +
                  "configured the device to use the Lawn wifi network and try again.");
              return;
            }
            try {
              Thread.sleep(1000);
            } catch (InterruptedException e) {}
            i++;
          }
        }
        
        //If not connected or if SSID of connected network is not GTwireless then fail
        if (!cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected() || 
            !wifi.getConnectionInfo().getSSID().equalsIgnoreCase(SSID)) {
          display("Device is not connected to the Lawn wifi network. Please connect to the proper network and try again.");
          return;
        }
        updateDialog("Authenticating...");
        String result = "";
        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost("https://auth.lawn.gatech.edu/index.php");
        try {
          //set up post parameters
          List<NameValuePair> data = new ArrayList<NameValuePair>(3);
          data.add(new BasicNameValuePair("username", user.getText().toString()));
          data.add(new BasicNameValuePair("password", pass.getText().toString()));
          data.add(new BasicNameValuePair("output", "text"));
          //check preferences for ISS status
          if (Prefs.getISS(c)) {
            Log.d("GTHive", "ISS ENABLED");
            data.add(new BasicNameValuePair("iss", "on"));
          }
          post.setEntity(new UrlEncodedFormEntity(data));
          
          ResponseHandler<String> rh = new BasicResponseHandler();
          result = client.execute(post,rh);
          
          //check text response and alert user of success/failure
          if (result.equals("Logging you into LAWN...")) {
            result = "Success!";
          }
          else if (result.equals("")) {
            result = "Already logged in.";
          } 
          display(result);
        }
        catch (UnsupportedEncodingException e) {
          Log.d(TAG, "UnsupportedEncodingException");
          display("Invalid characters, please re-enter information.");
        }
        catch (HttpResponseException e) {
          Log.d(TAG, "HttpResponseException");
          display("Lawn appears to be down, please try again later.");
        }
        catch (ClientProtocolException e) {
          Log.d(TAG, "ClientProtocolException");
          display("Could not connect to lawn, please try again later.");
        }
        catch (IOException e) {
          Log.d(TAG, "IOException");
          display("Connection interrupted, please try again.");
        }
        catch (Exception e) {
          Log.d(TAG, e.toString());
          display("Service appears down, please try again later.");
        }
      }
      
      /**
       * Updates the progress dialog message on the UI thread from within the
       * spawned network thread.
       * @param s the string to set the progress dialog message to
       */
      private void updateDialog(final String s) {
        runOnUiThread(new Runnable() {
          public void run() {
            dialog.setMessage(s);
          }
        });
      }
      
      /**
       * Displays a custom made toast notification (see notification.xml) to display
       * the result of the attempted login.
       * @param s the string the toast notification should display
       */
      private void display(final String s) {
        runOnUiThread(new Runnable() {
          public void run() {
            dialog.dismiss();
            Toast t = new Toast(GTHive.this);
            LayoutInflater inflater = getLayoutInflater();
            View layout = inflater.inflate(R.layout.notification,
                (ViewGroup) findViewById(R.id.layout_root));
            ((TextView)layout.findViewById(R.id.notification_text)).setText(s);
            layout.setBackgroundResource(android.R.drawable.toast_frame);
            t.setDuration(Toast.LENGTH_LONG);
            t.setView(layout);
            t.show();
          }
        });
      }
    }.start();
  }
  
  /**
   * Checks if wifi !enabled and preferences are set to NOT automatically enable
     * then show an AlertDialog to the user asking if wifi should be enabled.
   * If user selects yes then continue with login, if user cancels then
   * cancel with entire login process since it requires wifi.
   */
  private void checkWifi() {
    if (!((WifiManager)getSystemService(Context.WIFI_SERVICE)).isWifiEnabled()) {
      //check if preferences are set to NOT enable wifi automatically
      if (!Prefs.getAutoWifi(this)) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        //build alert dialog to display to user with callbacks
        builder.setTitle("Wifi is Currently Disabled")
             .setMessage("Wifi connection required. Enable wifi?")
               .setCancelable(false)
               .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface d, int id) {
                        d.cancel();
                   }
               })
               .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface d, int id) {
                        d.cancel();
                        dialog = ProgressDialog.show(GTHive.this, "",
                        "Enabling wifi...", true);
                        login();
                   }
               });
        AlertDialog alert = builder.create();
        alert.show();
      }
      else {
        //if autoWifi enabled then simply start progressDialog and call login()
        dialog = ProgressDialog.show(GTHive.this, "",
                "Enabling wifi...", true);
                login();
      }
    }
    else {
      //if wifi is enabled then start progressDialog and call login()
      dialog = ProgressDialog.show(GTHive.this, "",
            "Authenticating...", true);
      login();
    }
  }
  
  /**
   * Standard method, called when user presses menu button and displays
   * the menu defined in menu.xml
   */
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    MenuInflater mi = getMenuInflater();
    mi.inflate(R.menu.menu, menu);
    return true;
  }
  
  /**
   * Called when a menu item is pressed, checks which menu item was pressed
   * and calls the appropriate method.
   */
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch(item.getItemId()) {
    case R.id.settings:
      /*
       *  Need to check for result because user/pass might need to be reloaded
       *  upon completion in the case that user chose to clear all saved data.
       */
      startActivityForResult(new Intent(this, Prefs.class), CLEARED_DATA);
      return true;
    case R.id.quit:
      finish();
      return true;
    /*case R.id.email:
      //TODO this is not entirely supported yet and needs major work, see Web.java
      startActivity(new Intent(this, Web.class));
      return true;*/
    }
    return super.onOptionsItemSelected(item);
  }
  
  /**
   * Only used in the case of a user entering the preference screen, this method is
   * called when the Preference activity finishes and checks for a resultCode of
   * "333". This has been specially defined to denote that the user chose to clear
   * all saved data in GTHive so the username and password textfields are reloaded
   * so that the previously saved information is no longer displayed to the user since
   * it has been wiped from the program.
   */
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == CLEARED_DATA && resultCode == 333) {
      user.setText(settings.getString("user", ""));
          pass.setText(settings.getString("pass", ""));
    }
  }
  
  /**
   * Workaround for progressDialog errors on rotation changes. The issue occurs because
   * the progress dialog is started in the UI thread but on rotation change the UI is "reset"
   * automatically by Android. When the spawned network thread from {@link #login()} attempts
   * to update the progressDialog after this orientation change a null pointer error occurs
   * since the progress dialog no longer exists.
   */
  public void onConfigurationChanged(Configuration c) {
    super.onConfigurationChanged(c);
    switch (c.orientation) {
    case Configuration.ORIENTATION_PORTRAIT :
      findViewById(R.id.background).setBackgroundResource(R.drawable.stadiumsmall);
      break;
    case Configuration.ORIENTATION_LANDSCAPE :
      findViewById(R.id.background).setBackgroundResource(0);
      break;
    }
  }

  /**
   * Set newText variable to true if username or password textfields change so that the 
   * program knows it has to save the new information.
   */
  public void afterTextChanged(Editable s) {
    newText = true;
  }

  /** Unused. */
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

  /** Unused. */
  public void onTextChanged(CharSequence s, int start, int before, int count) {}
    
}




Java Source Code List

com.craigsc.gthive.GTHiveReceiver.java
com.craigsc.gthive.GTHive.java
com.craigsc.gthive.Prefs.java
com.craigsc.gthive.Web.java