Enhance: Update Google Play Games integration and versioning

- Incremented version code to 3 and version name to 0.2 in build.gradle.
- Added INTERNET and ACCESS_NETWORK_STATE permissions in AndroidManifest.xml.
- Refactored leaderboard display logic in HighScoresActivity and MainActivity to utilize a listener for intent success and failure.
- Introduced silent sign-in functionality for Google Play Games in MainActivity.
- Updated GooglePlayGamesManager to support the new listener interface for leaderboard intent handling.
- Added Google Play sign-in buttons in both portrait and landscape layouts for improved user interaction.
This commit is contained in:
cmclark00 2025-04-02 18:04:24 -04:00
parent 220caa39f7
commit 808dc79396
7 changed files with 143 additions and 26 deletions

View file

@ -11,8 +11,8 @@ android {
applicationId "com.pixelmintdrop"
minSdk 30
targetSdk 35
versionCode 2
versionName "0.1"
versionCode 3
versionName "0.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

View file

@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Add permission to handle system gestures if needed on some devices -->
<application
@ -14,6 +16,9 @@
<meta-data
android:name="com.google.android.gms.games.APP_ID"
android:value="@string/app_id" />
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<activity
android:name=".MainActivity"
android:exported="true"

View file

@ -7,6 +7,7 @@ import com.pixelmintdrop.databinding.HighScoresBinding
import com.pixelmintdrop.model.HighScoreAdapter
import com.pixelmintdrop.model.HighScoreManager
import com.pixelmintdrop.model.PlayerProgressionManager
import com.pixelmintdrop.model.GooglePlayGamesManager
import android.graphics.Color
import android.util.Log
import android.view.KeyEvent
@ -17,6 +18,7 @@ import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import android.content.Intent
class HighScoresActivity : AppCompatActivity() {
private lateinit var binding: HighScoresBinding
@ -25,6 +27,10 @@ class HighScoresActivity : AppCompatActivity() {
private lateinit var progressionManager: PlayerProgressionManager
private var currentTheme = PlayerProgressionManager.THEME_CLASSIC
companion object {
private const val RC_LEADERBOARD_UI_HS = 9005 // Unique request code for HighScoresActivity
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -136,8 +142,23 @@ class HighScoresActivity : AppCompatActivity() {
Toast.makeText(this, "Signing in to Google Play Games...", Toast.LENGTH_SHORT).show()
}
// Show the leaderboard
highScoreManager.getGooglePlayGamesManager().showLeaderboard(this)
// Call the updated showLeaderboard with a listener
highScoreManager.getGooglePlayGamesManager().showLeaderboard(this,
object : GooglePlayGamesManager.LeaderboardIntentListener {
override fun onLeaderboardIntentSuccess(intent: Intent) {
try {
startActivityForResult(intent, RC_LEADERBOARD_UI_HS)
} catch (e: Exception) {
Log.e("HighScoresActivity", "Failed to start leaderboard activity for result", e)
Toast.makeText(this@HighScoresActivity, "Could not display leaderboard.", Toast.LENGTH_SHORT).show()
}
}
override fun onLeaderboardIntentFailure(exception: Exception) {
Log.e("HighScoresActivity", "Failed to get leaderboard intent.", exception)
Toast.makeText(this@HighScoresActivity, "Could not display leaderboard.", Toast.LENGTH_SHORT).show()
}
})
} catch (e: Exception) {
Log.e("HighScoresActivity", "Error showing leaderboard", e)
Toast.makeText(this, "Could not open leaderboard", Toast.LENGTH_SHORT).show()

View file

@ -59,6 +59,10 @@ import kotlin.random.Random
import com.google.android.gms.games.PlayGames
import com.google.android.gms.games.PlayGamesSdk
import com.google.android.gms.games.GamesSignInClient
import com.google.android.gms.auth.api.signin.GoogleSignIn // Added for silent sign-in
import com.google.android.gms.auth.api.signin.GoogleSignInClient // Added for silent sign-in
import com.google.android.gms.auth.api.signin.GoogleSignInOptions // Added for silent sign-in
import com.pixelmintdrop.model.GooglePlayGamesManager // Added import for listener
class MainActivity : AppCompatActivity(),
GamepadController.GamepadConnectionListener,
@ -67,6 +71,7 @@ class MainActivity : AppCompatActivity(),
companion object {
private const val TAG = "MainActivity"
private const val RC_LEADERBOARD_UI = 9004 // Request code for leaderboard UI
}
// ViewModel
@ -74,6 +79,7 @@ class MainActivity : AppCompatActivity(),
// Google Play Games Services
private lateinit var gamesSignInClient: GamesSignInClient
private lateinit var googleSignInClient: GoogleSignInClient // Added for silent sign-in
// UI components
private lateinit var binding: ActivityMainBinding
@ -167,6 +173,9 @@ class MainActivity : AppCompatActivity(),
// Initialize Google Play Games Services
PlayGamesSdk.initialize(this)
gamesSignInClient = PlayGames.getGamesSignInClient(this)
// Initialize GoogleSignInClient for silent sign-in
val signInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN).build()
googleSignInClient = GoogleSignIn.getClient(this, signInOptions)
// Request sign-in silently
signInToPlayGames()
@ -2256,23 +2265,51 @@ class MainActivity : AppCompatActivity(),
// Method to show Google Play Games leaderboard
private fun showLeaderboard() {
gamesSignInClient.isAuthenticated.addOnCompleteListener { task ->
val isAuthenticated = task.isSuccessful && task.result.isAuthenticated
// New logic: Try silent sign-in first, then interactive if needed.
Log.d(TAG, "Attempting silent sign-in before showing leaderboard...")
// Use googleSignInClient for silentSignIn
googleSignInClient.silentSignIn().addOnCompleteListener { silentSignInTask ->
if (silentSignInTask.isSuccessful) {
// Silent sign-in successful OR user already signed in.
Log.d(TAG, "Silent sign-in successful/already signed in. Getting leaderboard intent.")
getAndShowLeaderboardIntent()
} else {
// Silent sign-in failed. Need explicit sign-in.
Log.w(TAG, "Silent sign-in failed. Attempting interactive sign-in.", silentSignInTask.exception)
// Use gamesSignInClient for interactive signIn
gamesSignInClient.signIn().addOnCompleteListener { interactiveSignInTask ->
if (interactiveSignInTask.isSuccessful) {
// Interactive sign-in successful
Log.d(TAG, "Interactive sign-in successful. Getting leaderboard intent.")
getAndShowLeaderboardIntent()
} else {
// Interactive sign-in failed
Log.e(TAG, "Interactive sign-in failed.", interactiveSignInTask.exception)
Toast.makeText(this, "Sign-in failed. Please try again.", Toast.LENGTH_SHORT).show()
}
}
}
}
}
if (isAuthenticated) {
// Show leaderboard
highScoreManager.getGooglePlayGamesManager().showLeaderboard(this)
} else {
// Sign in first
gamesSignInClient.signIn().addOnCompleteListener { signInTask ->
if (signInTask.isSuccessful) {
// Now try to show leaderboard again
highScoreManager.getGooglePlayGamesManager().showLeaderboard(this)
} else {
Toast.makeText(this, "Sign-in required to view leaderboard", Toast.LENGTH_SHORT).show()
}
}
// Helper function to get the intent from GooglePlayGamesManager and show it
private fun getAndShowLeaderboardIntent() {
highScoreManager.getGooglePlayGamesManager().showLeaderboard(this,
object : GooglePlayGamesManager.LeaderboardIntentListener {
override fun onLeaderboardIntentSuccess(intent: Intent) {
Log.d(TAG, "Received leaderboard intent, starting activity for result.")
try {
startActivityForResult(intent, RC_LEADERBOARD_UI)
} catch (e: Exception) {
Log.e(TAG, "Failed to start leaderboard activity for result", e)
Toast.makeText(this@MainActivity, "Could not display leaderboard.", Toast.LENGTH_SHORT).show()
}
}
override fun onLeaderboardIntentFailure(exception: Exception) {
Log.e(TAG, "Failed to get leaderboard intent.", exception)
Toast.makeText(this@MainActivity, "Could not display leaderboard.", Toast.LENGTH_SHORT).show()
}
})
}
}

View file

@ -16,6 +16,12 @@ import com.google.android.gms.tasks.Task
class GooglePlayGamesManager(private val context: Context) {
private val TAG = "GooglePlayGamesManager"
// Define a listener interface for the leaderboard intent
interface LeaderboardIntentListener {
fun onLeaderboardIntentSuccess(intent: Intent)
fun onLeaderboardIntentFailure(exception: Exception)
}
// Leaderboard ID
companion object {
const val LEADERBOARD_ID = "CgkImJW2mKsSEAIQAQ"
@ -71,26 +77,33 @@ class GooglePlayGamesManager(private val context: Context) {
}
}
// Show the leaderboard
fun showLeaderboard(activity: Activity) {
val account = GoogleSignIn.getLastSignedInAccount(context)
if (account == null) {
Log.w(TAG, "Not signed in, cannot show leaderboard")
return
}
// Show the leaderboard - Now uses a listener to return the Intent
fun showLeaderboard(activity: Activity, listener: LeaderboardIntentListener) {
Log.d(TAG, "showLeaderboard called in GooglePlayGamesManager")
Log.d(TAG, "Attempting to get LeaderboardsClient (assuming user is signed in)")
try {
val leaderboardsClient = PlayGames.getLeaderboardsClient(activity)
Log.d(TAG, "LeaderboardsClient obtained, attempting to get leaderboard intent for ID: $LEADERBOARD_ID")
leaderboardsClient
.getLeaderboardIntent(LEADERBOARD_ID)
.addOnSuccessListener { intent ->
activity.startActivity(intent)
Log.d(TAG, "Successfully obtained leaderboard intent. Calling listener.")
// try { // Removed - Activity start is now handled by MainActivity
// activity.startActivity(intent)
// Log.d(TAG, "Leaderboard activity started successfully.")
// } catch (e: Exception) {
// Log.e(TAG, "Error starting leaderboard activity", e)
// }
listener.onLeaderboardIntentSuccess(intent)
}
.addOnFailureListener { e ->
Log.e(TAG, "Error showing leaderboard", e)
Log.e(TAG, "Error getting leaderboard intent", e)
listener.onLeaderboardIntentFailure(e)
}
} catch (e: Exception) {
Log.e(TAG, "Error showing leaderboard", e)
Log.e(TAG, "Error obtaining LeaderboardsClient or getting leaderboard intent", e) // Updated log message
listener.onLeaderboardIntentFailure(e)
}
}
}

View file

@ -438,6 +438,34 @@
android:singleLine="true"
android:focusable="true"
android:focusableInTouchMode="true" />
<!-- Leaderboard Button -->
<Button
android:id="@+id/leaderboardButton"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@color/transparent"
android:text="Global Leaderboard"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
android:fontFamily="sans-serif"
android:textAllCaps="false" />
<!-- Google Play Sign In Button -->
<Button
android:id="@+id/googlePlaySignInButton"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@color/transparent"
android:text="Sign in to Google Play"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
android:fontFamily="sans-serif"
android:textAllCaps="false" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View file

@ -420,6 +420,19 @@
android:fontFamily="sans-serif"
android:textAllCaps="false" />
<Button
android:id="@+id/googlePlaySignInButton"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/transparent"
android:text="Sign in to Google Play"
android:textColor="@color/white"
android:textSize="24sp"
android:textStyle="bold"
android:fontFamily="sans-serif"
android:textAllCaps="false" />
<Button
android:id="@+id/statsButton"
android:layout_width="200dp"