title: Google Achievements Unlock But Don't Save
body: <p>I added achievements to my Google Play game following Google's tutorial. They unlock fine and if I display achievements in-game immediately they show up. If I quit the game and go to the Google Game's app they don't show up and they disappear from in-game also. Any ideas? I've tried multiple accounts. Thanks!</p>
  <pre><code>package com.b1stable.tth;
  
  import java.io.File;
  import java.io.FileFilter;
  import java.util.Locale;
  import java.nio.file.Path;
  import java.nio.file.PathMatcher;
  import java.nio.file.FileSystems;
  import java.util.Vector;
  
  import android.os.Bundle;
  import android.os.Build;
  import android.content.Context;
  import android.content.Intent;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.net.Uri;
  import android.os.Vibrator;
  import android.os.VibrationEffect;
  import android.util.Log;
  import android.view.Surface;
  import android.view.Gravity;
  
  import org.libsdl.app.SDLActivity; 
  
  import com.b1stable.tth.License_Viewer_Activity;
  
  import android.content.Intent;
  import android.os.Bundle;
  import android.util.Log;
  import android.widget.Toast;
  
  import androidx.annotation.NonNull;
  import androidx.appcompat.app.AlertDialog;
  import androidx.fragment.app.Fragment;
  import androidx.fragment.app.Fragment;
  import androidx.fragment.app.FragmentActivity;
  import com.google.android.gms.auth.api.signin.GoogleSignIn;
  import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
  import com.google.android.gms.auth.api.signin.GoogleSignInClient;
  import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
  import com.google.android.gms.auth.api.signin.GoogleSignInResult;
  import com.google.android.gms.auth.api.Auth;
  import com.google.android.gms.common.api.ApiException;
  import com.google.android.gms.games.AchievementsClient;
  import com.google.android.gms.games.AnnotatedData;
  import com.google.android.gms.games.EventsClient;
  import com.google.android.gms.games.Games;
  import com.google.android.gms.games.GamesClient;
  import com.google.android.gms.games.LeaderboardsClient;
  import com.google.android.gms.games.Player;
  import com.google.android.gms.games.PlayersClient;
  import com.google.android.gms.games.event.Event;
  import com.google.android.gms.games.event.EventBuffer;
  import com.google.android.gms.tasks.OnCompleteListener;
  import com.google.android.gms.tasks.OnFailureListener;
  import com.google.android.gms.tasks.OnSuccessListener;
  import com.google.android.gms.tasks.Task;
  import com.google.android.gms.tasks.Task.*;
  
  public class TTH_Activity extends SDLActivity
  {
      final static int LICENSE_REQUEST = 1;
  
      native static void resume_after_showing_license();
      native static void resume_after_showing_achievements();
      native static void pause();
      native static void resume();
  
      // Client used to sign in with Google APIs
      private GoogleSignInClient mGoogleSignInClient;
      private AchievementsClient mAchievementsClient = null;
      private boolean signin_failed = false;
  
      // request codes we use when invoking an external activity
      private static final int RC_UNUSED = 5001;
      private static final int RC_SIGN_IN = 9001;
  
      // This is so the screen is never cleared pure black, only shim::black (r:35, g:30, b:60)
      static boolean paused = false;
  
       private static final String TAG = &quot;TTH&quot;;
  
      @Override
      public void onCreate(Bundle savedInstance)
      {
          super.onCreate(savedInstance);
      }
  
      @Override
      public void onActivityResult(int requestCode, int resultCode, Intent data)
      {
          super.onActivityResult(requestCode, resultCode, data);
          if (requestCode == LICENSE_REQUEST) {
              if (data != null) {
                  if (resultCode == RESULT_OK &amp;&amp; data.getExtras().getString(&quot;MESSAGE&quot;).equals(&quot;OK&quot;)) {
                      show_license_result = 0;
                  }
                  else if (resultCode == RESULT_CANCELED &amp;&amp; data.getExtras().getString(&quot;MESSAGE&quot;).equals(&quot;FAIL&quot;)) {
                      show_license_result = 1;
                  }
                  else {
                      show_license_result = 1;
                  }
              }
              else {
                  show_license_result = 1;
              }
  
              resume_after_showing_license();
          }
          if (requestCode == RC_SIGN_IN) {
              GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
              if (result.isSuccess()) {
                  // The signed in account is stored in the result.
                  GoogleSignInAccount signedInAccount = result.getSignInAccount();
                  onConnected(signedInAccount);
              }
              else {
                  String message = result.getStatus().getStatusMessage();
                  if (message == null || message.isEmpty()) {
                      message = &quot;An error occurred!&quot;;
                  }
                  new AlertDialog.Builder(this).setMessage(message).setNeutralButton(android.R.string.ok, null).show();
                  onDisconnected();
              }
          }
      }
  
      public void onStart() {
          super.onStart();
      }
  
      @Override
      public void onStop()
      {
          super.onStop();
          pause();
      }
      
      @Override
      public void onRestart()
      {
          super.onRestart();
          resume();
      }
  
      @Override
      public void onResume()
      {
          super.onResume();
          signInSilently();
      }
  
      @Override
      public void onPause()
      {
          super.onPause();
          mAchievementsClient = null;
      }
  
      @Override
      public void onPostResume()
      {
          super.onPostResume();
          paused = true;
      }
  
      public void logString(String s)
      {
          Log.d(&quot;TTH&quot;, s);
      }
  
      public String getAppdataDir()
      {
          return getFilesDir().getAbsolutePath();
      }
      
      public String getSDCardDir()
      {
          File f = getExternalFilesDir(null);
          if (f != null) {
              return f.getAbsolutePath();
          }
          else {
              return getFilesDir().getAbsolutePath();
          }
      }
  
      static int show_license_result;
  
      public void showLicense()
      {
          show_license_result = -1;
          Intent intent = new Intent(this, License_Viewer_Activity.class);
          startActivityForResult(intent, LICENSE_REQUEST);
      }
  
      public int getShowLicenseResult()
      {
          return show_license_result;
      }
  
      /*
      public void openURL(String url)
      {
          Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
          startActivity(intent);
      }
      */
  
      public void rumble(int milliseconds)
      {
          Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
          if (v != null &amp;&amp; v.hasVibrator()) {
              if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
                  v.vibrate(VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE));
              }
              else {
                  v.vibrate(milliseconds);
              }
          }
      }
  
      public boolean has_touchscreen()
      {
          return getPackageManager().hasSystemFeature(&quot;android.hardware.touchscreen&quot;);
      }
  
      public boolean has_vibrator()
      {
          Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
          if (v != null) {
              return v.hasVibrator();
          }
          else {
              return false;
          }
      }
  
      public void start_draw()
      {
          if (paused) {
              paused = false;
          }
      }
      
      public String get_android_language()
      {
          return Locale.getDefault().getLanguage();
      }
  
      private static File[] list_dir_files = null;
  
      public void list_dir_start(String path)
      {
          try {
              int slash = path.lastIndexOf('/');
              final String glob = path.substring(slash+1).replace(&quot;*&quot;, &quot;.*&quot;); // +1 works even if not found (-1+1 == 0)
              String dir = path.substring(0, slash);
              File f = new File(dir);
              list_dir_files = f.listFiles(new FileFilter() {
                  public boolean accept(File f)
                  {
                      try {
                          if (f.getName().matches(glob)) {
                              return true;
                          }
                          else {
                              return false;
                          }
                      }
                      catch (Exception e) {
                          Log.d(&quot;TTH&quot;, &quot;list_dir_start FileFilter throwing &quot; + e.getMessage());
                          return false;
                      }
                  }
              });
          }
          catch (Exception e) {
              list_dir_files = null;
              Log.d(&quot;TTH&quot;, &quot;list_dir_start throwing &quot; + e.getMessage());
          }
      }
  
      public String list_dir_next()
      {
          if (list_dir_files == null) {
              return &quot;&quot;;
          }
          else if (list_dir_files.length == 0) {
              list_dir_files = null;
              return &quot;&quot;;
          }
          else {
              File f = list_dir_files[0];
              String name = f.getName();
              if (list_dir_files.length == 1) {
                  list_dir_files = null;
              }
              else {
                  File[] new_list = new File[list_dir_files.length-1];
                  for (int i = 1; i &lt; list_dir_files.length; i++) {
                      new_list[i-1] = list_dir_files[i];
                  }
                  list_dir_files = new_list;
              }
              return name;
          }
      }
  
      private static final String ARC_DEVICE_PATTERN = &quot;.+_cheets|cheets_.+&quot;;
  
      public boolean is_chromebook()
      {
          // Google uses this, so should work?
          return Build.DEVICE != null &amp;&amp; Build.DEVICE.matches(ARC_DEVICE_PATTERN);
      }
  
      private static final int RC_ACHIEVEMENT_UI = 9003;
  
      public boolean show_achievements()
      {
          if (mAchievementsClient == null) {
              return false;
          }
          mAchievementsClient.getAchievementsIntent().addOnSuccessListener(new OnSuccessListener&lt;Intent&gt;() {
              @Override
              public void onSuccess(Intent intent) {
                  startActivityForResult(intent, RC_ACHIEVEMENT_UI);
                  resume_after_showing_achievements();
              }
          }).addOnFailureListener(new OnFailureListener() {
              @Override
              public void onFailure(Exception e) {
                  resume_after_showing_achievements();
              }
          }).addOnCompleteListener(new OnCompleteListener&lt;Intent&gt;() {
              @Override
              public void onComplete(Task&lt;Intent&gt; task) {
                  resume_after_showing_achievements();
              }
          });
  
          return true;
      }
      
      public void achieve(String id)
      {
          if (mAchievementsClient != null) {
              mAchievementsClient.unlock(id);
          }
      }
  
      private void startSignInIntent() {
          GoogleSignInClient signInClient = GoogleSignIn.getClient(this, GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN);
          Intent intent = signInClient.getSignInIntent();
          startActivityForResult(intent, RC_SIGN_IN);
      }
  
      private void signInSilently() {
          if (signin_failed == true || mAchievementsClient != null) {
              return;
          }
  
          GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN;
          GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
          if (GoogleSignIn.hasPermissions(account, signInOptions.getScopeArray())) {
              // Already signed in.
              // The signed in account is stored in the 'account' variable.
              //GoogleSignInAccount signedInAccount = account;
              onConnected(account);
          }
          else {
              // Haven't been signed-in before. Try the silent sign-in first.
              GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOptions);
              signInClient.silentSignIn().addOnCompleteListener(
                  this,
                  new OnCompleteListener&lt;GoogleSignInAccount&gt;() {
                      @Override
                      public void onComplete(@NonNull Task&lt;GoogleSignInAccount&gt; task) {
                          if (task.isSuccessful()) {
                              // The signed in account is stored in the task's result.
                              GoogleSignInAccount signedInAccount = task.getResult();
                              onConnected(signedInAccount);
                          }
                          else {
                              // Player will need to sign-in explicitly using via UI.
                              // See [sign-in best practices](http://developers.google.com/games/services/checklist) for guidance on how and when to implement Interactive Sign-in,
                              // and [Performing Interactive Sign-in](http://developers.google.com/games/services/android/signin#performing_interactive_sign-in) for details on how to implement
                              // Interactive Sign-in.
                              startSignInIntent();
                          }
                      }
                  }
              );
          }
      }
  
      public void start_google_play_games_services() {
          /*
          runOnUiThread(new Runnable() {
              public void run() {
                  signInSilently();
              }
          });
          */
      }
  
      private void onConnected(GoogleSignInAccount googleSignInAccount) {
          Log.d(TAG, &quot;onConnected(): connected to Google APIs&quot;);
  
          GamesClient gamesClient = Games.getGamesClient(this, googleSignInAccount);
          gamesClient.setViewForPopups(findViewById(android.R.id.content));
          gamesClient.setGravityForPopups(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
  
          mAchievementsClient = Games.getAchievementsClient(this, googleSignInAccount);
      }
  
      private void onDisconnected() {
          Log.d(TAG, &quot;onDisconnected()&quot;);
  
          mAchievementsClient = null;
  
          signin_failed = true;
      }
  }
  </code></pre>