From 34a24149a9d2d2fd9e0edf3c656d37e0b3e73af0 Mon Sep 17 00:00:00 2001 From: Murray Cumming Date: Mon, 13 Apr 2015 11:31:06 +0200 Subject: [PATCH] Show Log Out instead of Login in menu when logged in. 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: https://github.com/zooniverse/Galaxy-Zoo/issues/184 This fixes this issue: https://github.com/murraycu/android-galaxyzoo/issues/18 --- .../murrayc/galaxyzoo/app/ListFragment.java | 1 - .../com/murrayc/galaxyzoo/app/LoginUtils.java | 81 ++++++++++++++++++- .../murrayc/galaxyzoo/app/ZooFragment.java | 61 ++++++++++++++ .../res/menu/actionbar_menu_item_common.xml | 4 + app/src/main/res/menu/actionbar_menu_list.xml | 3 + app/src/main/res/values/strings.xml | 3 + 6 files changed, 151 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/murrayc/galaxyzoo/app/ListFragment.java b/app/src/main/java/com/murrayc/galaxyzoo/app/ListFragment.java index 5c16d7aa..866ecde1 100644 --- a/app/src/main/java/com/murrayc/galaxyzoo/app/ListFragment.java +++ b/app/src/main/java/com/murrayc/galaxyzoo/app/ListFragment.java @@ -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; diff --git a/app/src/main/java/com/murrayc/galaxyzoo/app/LoginUtils.java b/app/src/main/java/com/murrayc/galaxyzoo/app/LoginUtils.java index 3718bf03..bfdd5816 100644 --- a/app/src/main/java/com/murrayc/galaxyzoo/app/LoginUtils.java +++ b/app/src/main/java/com/murrayc/galaxyzoo/app/LoginUtils.java @@ -24,6 +24,7 @@ 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; @@ -31,6 +32,7 @@ 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; @@ -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; } @@ -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. * @@ -436,6 +473,48 @@ protected void onCancelled() { } } + /** Run this to log out. + */ + private static class AccountRemoveTask extends AsyncTask { + + private final WeakReference 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; @@ -459,4 +538,4 @@ public String getName() { return name; } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/murrayc/galaxyzoo/app/ZooFragment.java b/app/src/main/java/com/murrayc/galaxyzoo/app/ZooFragment.java index f2ae60c1..3747d2cb 100644 --- a/app/src/main/java/com/murrayc/galaxyzoo/app/ZooFragment.java +++ b/app/src/main/java/com/murrayc/galaxyzoo/app/ZooFragment.java @@ -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) { @@ -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; @@ -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(); @@ -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); diff --git a/app/src/main/res/menu/actionbar_menu_item_common.xml b/app/src/main/res/menu/actionbar_menu_item_common.xml index dab10c87..74fa9389 100644 --- a/app/src/main/res/menu/actionbar_menu_item_common.xml +++ b/app/src/main/res/menu/actionbar_menu_item_common.xml @@ -5,6 +5,10 @@ android:id="@+id/option_menu_item_login" android:title="@string/action_login" android:orderInCategory="7" /> + + Login + + Log out + Favorite