Many applications require users to login in order to access all the available features. In this tutorial we will secure an Android activity by requiring users to enter their username and password.

We will start by creating a new blank activity with fragment, LoginActivity.

We will use the following layout for the login fragment (2 edit texts for username & password, 1 button to submit the login form and one text view to show any errors that could happen):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.sendgrid.android.sendgrid.app.LoginActivity$PlaceholderFragment">

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textEmailAddress"
        android:ems="10"
        android:id="@+id/username"
        android:hint="Username"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textPassword"
        android:ems="10"
        android:id="@+id/password"
        android:layout_below="@+id/username"
        android:layout_alignLeft="@+id/editText"
        android:layout_alignStart="@+id/editText"
        android:hint="Password" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login"
        android:id="@+id/button"
        android:layout_below="@+id/password"
        android:layout_alignLeft="@+id/editText2"
        android:layout_alignStart="@+id/editText2"
        android:layout_alignRight="@+id/editText2"
        android:layout_alignEnd="@+id/editText2"
        android:onClick="tryLogin"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=""
        android:id="@+id/error"
        android:layout_above="@+id/username"
        android:layout_centerHorizontal="true"
        android:textColor="#ffff0000" />

</RelativeLayout>

Before writing the actual login code, we will create a helper class to read & save related values to Android’s SharedPreferences:

public class Utility {
    public static Boolean isUserLoggedIn(Context context) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);

        return prefs.getBoolean("isUserLoggedIn", false);
    }

    public static void setUserLoggedIn(Context context, Boolean isLoggedIn)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean("isUserLoggedIn", isLoggedIn);
        editor.commit();
    }

    public static void logout(Context context) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean("isUserLoggedIn", false);
        editor.commit();
    }

    public static void saveUsernameAndPassword(Context context, String username, String password)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString("username", username);
        editor.putString("password", password);
        editor.commit();
    }
}

Now let’s see the actual login code:

public class LoginActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new LoginFragment())
                    .commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return false;
    }

    public void tryLogin(View view) {
        LoginFragment fragment = (LoginFragment) getSupportFragmentManager().findFragmentById(R.id.container);
        fragment.tryLogin(view);
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class LoginFragment extends Fragment {

        public LoginFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_login, container, false);
            return rootView;
        }

        public void login(Boolean result)
        {
            Utility.setUserLoggedIn(getActivity(), result);
            if(result) {
                EditText user = (EditText)getActivity().findViewById(R.id.username);
                EditText pass = (EditText)getActivity().findViewById(R.id.password);
                String username = user.getText().toString();
                String password = pass.getText().toString();
                Utility.saveUsernameAndPassword(getActivity(), username, password);

                getActivity().finish();
            } else {
                Utility.saveUsernameAndPassword(getActivity(), null, null);
                TextView error = (TextView)getActivity().findViewById(R.id.error);
                error.setText("Login failed! Please try again.");
            }
        }

        public void tryLogin(View view) {
            EditText user = (EditText)getActivity().findViewById(R.id.username);
            EditText pass = (EditText)getActivity().findViewById(R.id.password);
            String username = username.getText().toString();
            String password = password.getText().toString();

            if(!username.isEmpty() && !password.isEmpty()) {
                TextView error = (TextView)getActivity().findViewById(R.id.error);
                error.setText("");
                CheckLoginTask loginTask = new CheckLoginTask();
                loginTask.execute(username, password);
            }
        }

        // we will use an AsyncTask to connect to an API service to check the username and the password
        // the doInBackground method will return true if the login succeeds
        public class CheckLoginTask extends AsyncTask<String, Void, Boolean> {
            @Override
            protected Boolean doInBackground(String... params) {
                HttpsURLConnection urlConnection = null;
                BufferedReader reader = null;
                String responseJsonStr = null;

                try {
                    // Construct the URL for the get User query
                    final String GET_PROFILE_BASE_URL ="https://api.domain.com/user?";
                    Uri builtUri = Uri.parse(GET_PROFILE_BASE_URL).buildUpon().build();
                    URL url = new URL(builtUri.toString());
                    // Create the request to server and open the connection
                    urlConnection = (HttpsURLConnection) url.openConnection();
                    // Create the SSL connection
                    SSLContext sc;
                    sc = SSLContext.getInstance("TLS");
                    sc.init(null, null, new SecureRandom());
                    urlConnection.setSSLSocketFactory(sc.getSocketFactory());
                    // Add API credentials
                    String user = params[0];
                    String password = params[1];
                    String userpass = user + ":" + password;
                    // Create the Authentication Token
                    String basicAuth = "Basic " + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT);
                    // Add the required Headers.
                    urlConnection.addRequestProperty("Authorization", basicAuth);
                    urlConnection.addRequestProperty("Content-Type", "application/json");
                    urlConnection.setRequestProperty("accept", "application/json");
                    // Method
                    urlConnection.setRequestMethod("GET");
                    // Connect
                    urlConnection.connect();

                    int status = urlConnection.getResponseCode();
                    String reason = urlConnection.getResponseMessage();

                    Log.v("LOGIN", status + reason);

                    // Read the input stream into a String
                    InputStream inputStream = urlConnection.getInputStream();
                    StringBuffer buffer = new StringBuffer();
                    if (inputStream == null) {
                        // Nothing to do here
                        return null;
                    }
                    reader = new BufferedReader(new InputStreamReader(inputStream));

                    String line;
                    while ((line = reader.readLine()) != null) {
                        // Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
                        // But it does make debugging a *lot* easier if you print out the completed
                        // buffer for debugging.
                        buffer.append(line + "\n");
                    }

                    if (buffer.length() == 0) {
                        // Stream was empty. No point in parsing.
                        return null;
                    }
                    responseJsonStr = buffer.toString();
                    getNameDataFromJson(responseJsonStr);

                } catch (IOException | NoSuchAlgorithmException | JSONException | KeyManagementException e) {
                    Log.e("LOGIN", "Error", e);

                    return false;
                } finally {
                    if (urlConnection != null) {
                        urlConnection.disconnect();
                    }
                    if (reader != null) {
                        try {
                            reader.close();
                        } catch (final IOException e) {

                        }
                    }
                }

                // if we reach here it means we successfully logged in
                return true;
            }

            @Override
            protected void onPostExecute(Boolean result) {
                super.onPostExecute(result);
                login(result);
            }
        }
    }

}

In the end, all that’s left is to start this activity whenever we need the user to login:

public class MainActivity extends Activity {
    // ...

    @Override
    protected void onResume() {
        super.onResume();

        if(!Utility.isUserLoggedIn(this)){
            startActivity(new Intent(this, LoginActivity.class));
        }
    }

    // ...
}