Skip to content

Commit

Permalink
Show Log Out instead of Login in menu when logged in.
Browse files Browse the repository at this point in the history
By asynchronously caching the login status (async because we are asking
the AccountManager, not being we are asking the server) in onResume()
and using that in onPrepareOptionsMenu().
However, this will incorrectly show the user as logged in if they
change their password on the web server - clients have no way
to check that the api_key is still valid, even when using the api_key
to submit a classification:
zooniverse/Galaxy-Zoo#184

This fixes this issue:
#18
  • Loading branch information
murraycu committed May 21, 2015
1 parent 7807ac5 commit 34a2414
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ public View onCreateView(final LayoutInflater inflater, final ViewGroup containe
final Bundle savedInstanceState) {
// We would only call the base class's onCreateView if we wanted the default layout:
// super.onCreateView(inflater, container, savedInstanceState);

mRootView = inflater.inflate(R.layout.fragment_list, container, false);
assert mRootView != null;

Expand Down
81 changes: 80 additions & 1 deletion app/src/main/java/com/murrayc/galaxyzoo/app/LoginUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.util.JsonReader;

Expand Down Expand Up @@ -69,6 +71,17 @@ public final class LoginUtils {
*/
public static boolean getLoggedIn(final Context context) {
final LoginDetails loginDetails = getAccountLoginDetails(context);
return getLoggedIn(loginDetails);
}

/**
* This is a just a utility method that examines the LoginDetails.
* Unlike getLoggedIn(Context), this can be called from any thread.
*
* @param loginDetails
* @return
*/
public static boolean getLoggedIn(final LoginDetails loginDetails) {
if (loginDetails == null) {
return false;
}
Expand Down Expand Up @@ -184,6 +197,30 @@ public static LoginDetails getAccountLoginDetails(final Context context) {
}
}

public static void logOut(final ZooFragment fragment) {
final Activity activity = fragment.getActivity();
final AccountRemoveTask task = new AccountRemoveTask(activity) {
@Override
protected void onPostExecute(final Void result) {
super.onPostExecute(result);

//Make sure that the currently-shown menu will update:
fragment.setLoggedIn(false);

//TODO: This doesn't actually seem to cause the (various) child fragments'
//onPrepareOptionsMenu() methods to be called. Maybe it doesn't work with
//nested child fragments.
if (activity instanceof FragmentActivity) {
final FragmentActivity fragmentActivity = (FragmentActivity) activity;
fragmentActivity.supportInvalidateOptionsMenu();
} else {
activity.invalidateOptionsMenu();
}
}
};
task.execute();
}

/**
* Add the anonymous Account.
*
Expand Down Expand Up @@ -436,6 +473,48 @@ protected void onCancelled() {
}
}

/** Run this to log out.
*/
private static class AccountRemoveTask extends AsyncTask<Void, Void, Void> {

private final WeakReference<Context> contextReference;

AccountRemoveTask(final Context context) {
this.contextReference = new WeakReference<>(context);
}

@Override
protected Void doInBackground(final Void... params) {

if (contextReference == null) {
return null;
}

final Context context = contextReference.get();
if (context == null) {
return null;
}

LoginUtils.LoginDetails loginDetails = LoginUtils.getAccountLoginDetails(context);
if(!LoginUtils.getLoggedIn(loginDetails)) {
return null;
}

final String accountName = loginDetails.name;
if (TextUtils.isEmpty(accountName)) {
return null;
}

final AccountManager accountManager = AccountManager.get(context);
LoginUtils.removeAccount(context, accountName);

LoginUtils.addAnonymousAccount(context);

return null;
}
}


public static class LoginResult {
private final boolean success;
private final String name;
Expand All @@ -459,4 +538,4 @@ public String getName() {
return name;
}
}
}
}
61 changes: 61 additions & 0 deletions app/src/main/java/com/murrayc/galaxyzoo/app/ZooFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,54 @@

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
* Created by murrayc on 8/7/14.
*/
public class ZooFragment extends Fragment {
private boolean loggedIn = false;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}

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

cacheLoggedInStatus();
}

/** Asynchronously cache the log in status in loggedIn.
* Derived classes can call this in their onCreateView.
**/
protected void cacheLoggedInStatus() {
final LoginUtils.GetExistingLogin task = new LoginUtils.GetExistingLogin(getActivity()) {
@Override
protected void onPostExecute(final LoginUtils.LoginDetails loginDetails) {
super.onPostExecute(loginDetails);

ZooFragment.this.setLoggedIn(LoginUtils.getLoggedIn(loginDetails));
}
};
task.execute();
}

public void setLoggedIn(boolean loggedIn) {
this.loggedIn = loggedIn;
}

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
Expand All @@ -42,6 +77,9 @@ public boolean onOptionsItemSelected(final MenuItem item) {
case R.id.option_menu_item_login:
requestLogin();
return true;
case R.id.option_menu_item_logout:
requestLogout();
return true;
case R.id.option_menu_item_about:
showAbout();
return true;
Expand All @@ -53,6 +91,25 @@ public boolean onOptionsItemSelected(final MenuItem item) {
}
}

@Override
public void onPrepareOptionsMenu(final Menu menu) {
super.onPrepareOptionsMenu(menu);

//Before the menu item is displayed,
//show either "Log in" or "Log out":
//This depends on cacheLoggedInStatus() having been called in onResume().
final MenuItem itemLogin = menu.findItem(R.id.option_menu_item_login);
final MenuItem itemLogout = menu.findItem(R.id.option_menu_item_logout);

if ((itemLogin == null) || (itemLogout == null)) {
Log.error("onPrepareOptionsMenu(): Could not find menu items.");
return;
}

itemLogin.setVisible(!loggedIn);
itemLogout.setVisible(loggedIn);
}

/*
void requestMoreItems() {
final Activity activity = getActivity();
Expand All @@ -78,6 +135,10 @@ private void requestLogin() {
startActivity(intent);
}

private void requestLogout() {
LoginUtils.logOut(this);
}

private void showAbout() {
final Activity activity = getActivity();
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/menu/actionbar_menu_item_common.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
android:id="@+id/option_menu_item_login"
android:title="@string/action_login"
android:orderInCategory="7" />
<item
android:id="@+id/option_menu_item_logout"
android:title="@string/action_logout"
android:orderInCategory="7" />
<item
android:id="@+id/option_menu_item_list"
android:title="@string/action_list"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/menu/actionbar_menu_list.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
<item
android:id="@+id/option_menu_item_login"
android:title="@string/action_login" />
<item
android:id="@+id/option_menu_item_logout"
android:title="@string/action_logout" />
<!-- The More action is only useful for debugging:
<item
android:id="@+id/option_menu_item_more"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
<!-- An action. Shown on a button or menu item. -->
<string name="action_login">Login</string>

<!-- An action. Shown on a button or menu item. -->
<string name="action_logout">Log out</string>

<!-- A checkable action with two states. It is either a favorite or not. Shown on a button or menu item. -->
<string name="action_favorite">Favorite</string>

Expand Down

0 comments on commit 34a2414

Please sign in to comment.