0

I'm currently working on an game where I find myself in need of a dynamic options menu after implementing Google Play Game Services. My entire game consists of strings.xml and 6 Activities (not including imported library projects). I mention this only because it means I am building the options menu without using a layout.xml.

What I'm trying to accomplish is changing the visible state of my signin and signout buttons based upon the users logged in status. Currently when a user signs in the menu correctly updates itself and the Sign In button is replaced by Sign Out. However when the Sign Out button is clicked, while it does correctly sign the user out, it does not trigger the menu update. Attempting to Sign Out again via the button causes the application to crash because I'm not catching the exception, this I can deal with later. The menu does update properly if you change Activities.

What I've got so far looks remarkably similar to what I found here

This is my Extensions class which every other class extends to make use of methods common throughout my game, I have stripped the items unrelated to the menu.

package com.domain.myapp;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Build;
import android.view.Menu;
import android.view.MenuItem;

public abstract class Extensions extends LicenseCheck {
    private static final int SOM1= 1;
    private static final int SOM2= 2;
    private static final int SOM3= 3;
    private static final int SOM4= 4;
    private static final int SOM5= 5;
    private static final int SOM6= 6;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (Build.VERSION.SDK_INT >= 11) {
            buildMenu(menu);
        }
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (Build.VERSION.SDK_INT < 11) {
            buildMenu(menu);
        }
        return true;
    }

    private void buildMenu(Menu menu) {
        menu.clear();
        menu.add(Menu.NONE, SOM1, Menu.NONE, "Instructions");
        menu.add(Menu.NONE, SOM2, Menu.NONE, "View Achievements");
        menu.add(Menu.NONE, SOM3, Menu.NONE, "View Leaderboard");
        menu.add(Menu.NONE, SOM4, Menu.NONE, "Sign In");
        menu.add(Menu.NONE, SOM5, Menu.NONE, "Sign Out");
        menu.add(Menu.NONE, SOM6, Menu.NONE, "Exit Game");
        if (isSignedIn()) {
            menu.findItem(SOM4).setVisible(false);
            menu.findItem(SOM5).setVisible(true);
        }
        if (!isSignedIn()) {
                menu.findItem(SOM4).setVisible(true);
                menu.findItem(SOM5).setVisible(false);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case SOM1:
            Intent nextInstructionScreen = new Intent(getApplicationContext(), InstructionScreen.class);
            startActivity(nextInstructionScreen);   
            break;
        case SOM2:
            viewAchievements();
            break;
        case SOM3:
            viewLeaderboards();
            break;
        case SOM4:
            beginUserInitiatedSignIn();
            break;
        case SOM5:
            getGamesClient().signOut();
            menuRefresh();
            break;
        case SOM6:
            moveTaskToBack(true);
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    @SuppressLint("NewApi")
    public void menuRefresh() {
        if (Build.VERSION.SDK_INT >= 11) {
            invalidateOptionsMenu();
        }
    }
}

Additionally, I spent some time trying to use onSignOutComplete() but must have been doing that wrong. Any help would be greatly appreciated. Using a boolean to track login status did not change the behavior at all either. I can't figure out why the Sign Out button won't hide after it is used to sign out and make the Sign In button visible, when the opposite functionality works just fine.

Community
  • 1
  • 1
DRW
  • 1
  • 1
  • 1

1 Answers1

0

Personally, I'd stick with only using onCreateOptionsMenu() and remove the onPrepareOptionsMenu() method.

onPrepareOptionsMenu() is called every time the menu is displayed, whereas onCreateOptionsMenu() is only called when the menu is created initially and when you manually call invalidateOptionsMenu().

Also, instead of first adding both menu items and then remove / hide one of them, I'd simply check if the user is signed in and then add the appropriate menu.

In additional to that, although it really isn't related to your question, you should use string ressources instead of hardcoding your menu item titles. Check your res/values/strings.xml file and then grab the strings from there using getString(R.string.id_of_string) in your Java code.

PS. I'm guessing that your LicenseCheck class extends Activity?

Michell Bak
  • 13,182
  • 11
  • 64
  • 121
  • IIRC as of 3.0 Honeycomb (API 11) the options menu is always open once created, so onPrepareOptionsMenu() will not update it unless you first call invalidateOptionsMenu() - also, the reason I add both and then hide one or the other is so that users can sign in or out of my application at will. Sometimes you don't want the possibility of accidental sharing of achievements or scores to give away the time you are spending in a game. When my users are signed out they are no longer able to share scores or or submit to leaderboards, and achievements will be granted on their next sign in. – DRW Jun 27 '13 at 07:02
  • To answer your last question, the inheritance chain of my classes (for my MainActivity and the other three classes not named here in my game) is MainActivity => Extensions => LicenseCheck => BaseGameActivity – DRW Jun 27 '13 at 07:11
  • Yes, onPrepareOptionsMenu() is called when you invalidate the options menu, but so is onCreateOptionsMenu(). You only need onCreateOptionsMenu(), so it's safe to remove the other one. I still don't see why you can't do as I suggest in regards to the menu items. Simply have a check in your onCreateOptionsMenu(), and invalidate the menu every time it needs to change from "Log in" to "Log out". – Michell Bak Jun 27 '13 at 08:18
  • What you suggest is basically what is happening anyway. onPrepareOptionsMenu is ONLY being called if SDK < 11 because onCreateOptionsMenu will not be called again and invalidateOptionsMenu did not exist pre SDK 11. Likewise, onCreateOptionsMenu is only being used if SDK >= 11 because onPrepareOptionsMenu behaves differently, but you can use invalidateOptionsMenu to force onCreateOptionsMenu to be called again. In either case though I point BOTH to the buildMenu method so I get consistent menu behavior across all devices. – DRW Jun 27 '13 at 17:13
  • buildMenu clears the menu before rebuilding. Currently it adds all options and does a login check to determine which sign in/out option to show. Because the login check is within the same method as menu construction (buildMenu) I do not think that moving the login check to handle menu.add would give any different result than leaving it to handle menu.findItem().setVisibile() as it does currently. Regardless, I'll switch the check for login status within buildMenu to handle menu.add as you suggest and see if there is any difference. – DRW Jun 27 '13 at 17:17
  • Problem solved. Removed (isSignedIn()) and used a variable instead. Replaced getGamesClient().signOut(); with mHelper.signOut(); and that resulted in the user actually being signed out instead of the app just thinking it was signed out. variable controlled with onSignInSucceeded() and onSignOutComplete(). App behaves properly now for anything >= API 8 – DRW Jun 28 '13 at 07:36