I am a starter with Libgdx and Android.
I have developed a small game.
I have tried following up Google play game services tutorial at https://github.com/TheInvader360/libgdx-gameservices-tutorial using super jumper example. I have also checked every thing on Google developers Documentation.Also I have followed this tutorial
http://forum.xda-developers.com/android/apps-games/setting-eclipse-to-google-play-game-t2889796 Plus stack overflow.
a. SHA1 key is same when application Is EXPORT from eclipse.
b. Client ID is generated by O Auth2.0
c. Application package name is same .
d. My game is already published.
e. I also published Google play Game Services.(Its written on Google developer documentation that if app is published then also publish game services)
f. I upload Signed apk generated by Eclipse on my device for testing.
but no luck.
The error I got is that "Failed to sign in. Please check your network connection and try again. "
My application Manifest file is
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="...."
android:versionCode="1"
android:versionName="1.1" >
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="20" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
......>
<activity ....../>
<meta-data
android:name="com.google.android.gms.analytics.globalConfigResource"
android:resource="#xml/global_tracker" />
<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"/>
</application>
</manifest>
the configuration that I gave in my main Android Class is
public class AndroidLauncher extends AndroidApplication implements
ActionResolver, GameHelperListener , GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private GameHelper gameHelper;
private GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
client = new GoogleApiClient.Builder(this)
.addApi(Games.API)
.addScope(Games.SCOPE_GAMES)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
GameHelper.GameHelperListener gameHelperListener = new GameHelper.GameHelperListener() {
#Override
public void onSignInFailed() {
Log.i("Game Helper", "Sign in failed");
}
#Override
public void onSignInSucceeded() {
Log.i("Game Helper", "Sign in succeeded");
}
};
gameHelper = new GameHelper(this, GameHelper.CLIENT_GAMES);
gameHelper.enableDebugLog(true);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
initialize(new MainGame(this) , config);
gameHelper.setup(gameHelperListener );
}
#Override
public void onStart() {
super.onStart();
gameHelper.onStart(this);
client.connect();
}
#Override
public void onStop() {
super.onStop();
gameHelper.onStop();
client.disconnect();
}
#Override
public void onActivityResult(int request, int response, Intent data) {
super.onActivityResult(request, response, data);
gameHelper.onActivityResult(request, response, data);
}
#Override
public boolean getSignedInGPGS() {
return gameHelper.isSignedIn();
}
#Override
public void loginGPGS() {
try {
runOnUiThread(new Runnable() {
public void run() {
gameHelper.beginUserInitiatedSignIn();
}
});
} catch (final Exception ex) {
}
}
#Override
public void unlockAchievementGPGS(String achievementId) {
Games.Achievements.unlock(gameHelper.getApiClient(), achievementId);
}
#Override
public void getLeaderboardGPGS() {
}
#Override
public void getAchievementsGPGS() {
if (gameHelper.isSignedIn()) {
startActivityForResult(
Games.Achievements.getAchievementsIntent(gameHelper
.getApiClient()), 101);
} else if (!gameHelper.isConnecting()) {
loginGPGS();
}
}
#Override
public void onSignInFailed() {
System.out.println("Sign in succeeded");
}
#Override
public void onSignInSucceeded() {
System.out.println("Sign in failed");
}
#Override
public void submitScoreGPGS(int score) {
// TODO Auto-generated method stub
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
}
#Override
public void onConnected(Bundle arg0) {
Log.i("Google API", "Connection Complete");
}
#Override
public void onConnectionSuspended(int arg0) {
Log.i("Google API", "Connection Failed: " );
}
}
I have given the exact same app id in my string file in the resource folder.
I dont get it why I get this error.
action resolver interface has all the methods specified. Main Game class initiate this interface.
On Game over I send score to unlock achievements.
I only have Achievements in my game.
Any other piece of Code is needed I can provide but kindly help me out.
Here are a few points that might help you.
It takes several hours before your changes on Developer Console are actually published. Test the game after a few hours.
You don't need to publish in order to test it. You can do that by adding tester accounts in your developer console.
You can't "test" Google Play Services with developer account. You will need another account for that.
Edit:
Very Important:
Make sure you added required permissions to AndroidManifest.xml in your Android project.
Related
I am trying to add dynamic feature support to my app, so I created a test app.
The test app has a main app part that loads a dynamic feature and try to execute it.
The feature module has MainActivityCalled as main activity.
What I get is that the feature loading process works because I get successful log messages, and I get the list of installed modules.
Note that the app is run on a virtual device and no real download happens, I thinks everything gets installed automatically by deployment procedure from AndroidStudio.
The fact is that I get this kind of error when trying to call the main activity of the module:
W/System.err: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.dynamicfeature1/MainActivityCalled}; have you declared this activity in your AndroidManifest.xml?
W/System.err: at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1805)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1523)
at android.app.Activity.startActivityForResult(Activity.java:4225)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:767)
at android.app.Activity.startActivityForResult(Activity.java:4183)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:754)
at android.app.Activity.startActivity(Activity.java:4522)
at android.app.Activity.startActivity(Activity.java:4490)
at com.example.mymodules.MainActivity$2.onClick(MainActivity.java:227)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
Everything is done as in the documentation at https://developer.android.com/guide/app-bundle/playcore#java
except for the explicit call to the module activity that I guessed has to be performed with an intent (no example in the above linked page).
Important part of the code you find below are:
new OnSuccessListener<Integer>() {
#Override
public void onSuccess(Integer result) {
Log.d("request feature load","success "+result);
mySessionId=result;
Set<String> installedModules = splitInstallManager.getInstalledModules();
String[] modules = new String[installedModules.size()];
installedModules.toArray(modules);
for (int i=0;i<modules.length;i++)
{
Log.d("module",modules[i]);
}
}
})
that is OK.
Then
Button button2 = findViewById(R.id.fab2);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("feature1","called");
Intent intent=new Intent();
intent.setClassName("com.example.dynamicfeature1","MainActivityCalled");
try{ startActivity(intent);}
catch (Exception e){
e.printStackTrace();
}
}
});
All main activities has this overidden method
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Emulates installation of on demand modules using SplitCompat.
SplitCompat.installActivity(this);
Log.d("attachBaseContext",base.getPackageName().toString());
}
that is not called in the dynamic feature module when installed.
What is wrong with my code?
This is the Mainactivity of the app
package com.example.mymodules;
...imports...
public class MainActivity extends AppCompatActivity {
private static int MY_REQUEST_CODE=1;
Activity activity;
int mySessionId;
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Emulates installation of future on demand modules using SplitCompat.
SplitCompat.install(this);
Log.d("attachBaseContext",base.getPackageName().toString());
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_REQUEST_CODE) {
// Handle the user's decision. For example, if the user selects "Cancel",
// you may want to disable certain functionality that depends on the module.
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Button button1 = findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Creates an instance of SplitInstallManager.
final SplitInstallManager splitInstallManager =
SplitInstallManagerFactory.create(activity);
// Creates a request to install a module.
SplitInstallRequest request =
SplitInstallRequest
.newBuilder()
// You can download multiple on demand modules per
// request by invoking the following method for each
// module you want to install.
.addModule("dynamicfeature1")
.build();
// Creates a listener for request status updates.
SplitInstallStateUpdatedListener listener =new SplitInstallStateUpdatedListener() {
#Override
public void onStateUpdate(SplitInstallSessionState state) {
if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
// Displays a dialog for the user to either “Download”
// or “Cancel” the request.
try {
splitInstallManager.startConfirmationDialogForResult(
state,
/* activity = */ activity,
// You use this request code to later retrieve the user's decision.
/* requestCode = */ MY_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
if (state.sessionId() == mySessionId) {
switch (state.status()) {
case SplitInstallSessionStatus.INSTALLED:
Context tempNewContext=null;
try {
tempNewContext = activity.createPackageContext(activity.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
}
final Context newContext =tempNewContext;
// If you use AssetManager to access your app’s raw asset files, you’ll need
// to generate a new AssetManager instance from the updated context.
AssetManager am = newContext.getAssets();
if (BuildCompat.isAtLeastO()) {
// Updates the app’s context with the code and resources of the
// installed module.
SplitInstallHelper.updateAppInfo(newContext);
new Handler().post(new Runnable() {
#Override public void run() {
// Loads contents from the module using AssetManager
AssetManager am = newContext.getAssets();
}
});
} else
{SplitInstallHelper.updateAppInfo(newContext);}
}
}
}
} ;
splitInstallManager.registerListener(listener);
splitInstallManager
// Submits the request to install the module through the
// asynchronous startInstall() task. Your app needs to be
// in the foreground to submit the request.
.startInstall(request)
// You should also be able to gracefully handle
// request state changes and errors. To learn more, go to
// the section about how to Monitor the request state.
.addOnSuccessListener(new OnSuccessListener<Integer>() {
#Override
public void onSuccess(Integer result) {
Log.d("request feature load","success "+result);
mySessionId=result;
Set<String> installedModules = splitInstallManager.getInstalledModules();
String[] modules = new String[installedModules.size()];
installedModules.toArray(modules);
for (int i=0;i<modules.length;i++)
{
Log.d("module",modules[i]);
}
}
})
.addOnFailureListener(new OnFailureListener() {
void checkForActiveDownloads() {
splitInstallManager
// Returns a SplitInstallSessionState object for each active session as a List.
.getSessionStates()
.addOnCompleteListener(
new OnCompleteListener<List<SplitInstallSessionState>>() {
#Override
public void onComplete(Task<List<SplitInstallSessionState>> task) {
if (task.isSuccessful()) {
// Check for active sessions.
for (SplitInstallSessionState state : task.getResult()) {
if (state.status() == SplitInstallSessionStatus.DOWNLOADING) {
// Cancel the request, or request a deferred installation.
}
}
}
}
});
}
#Override
public void onFailure(Exception e) {
Log.d("request feature load","failure "+e.getMessage());
switch (((SplitInstallException) e).getErrorCode()) {
case SplitInstallErrorCode.NETWORK_ERROR:
// Display a message that requests the user to establish a
// network connection.
break;
case SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED:
checkForActiveDownloads();
}
}
});
}
});
Button button2 = findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("feature1","called");
Intent intent=new Intent();
intent.setClassName("com.example.dynamicfeature1","MainActivityCalled");
try{ startActivity(intent);}
catch (Exception e){
e.printStackTrace();
}
}
});
Button button3 = findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("feature2","called");
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
here's the main app manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.example.mymodules">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name="com.google.android.play.core.splitcompat.SplitCompatApplication"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Then there is the MainActivity of the dyamic feature module
package com.example.dynamicfeature1;
...imports...
public class MainActivityCalled extends AppCompatActivity {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Emulates installation of on demand modules using SplitCompat.
SplitCompat.installActivity(this);
Log.d("attachBaseContext",base.getPackageName().toString());
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "1-Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
}
and the module manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.example.dynamicfeature1">
<dist:module
dist:instant="false"
dist:title="#string/title_dynamicfeature1">
<dist:delivery>
<dist:on-demand />
</dist:delivery>
<dist:fusing dist:include="false" />
</dist:module>
<application>
<activity
android:name=".MainActivityCalled"
android:label="#string/title_activity_main"
android:theme="#style/AppTheme.NoActionBar"></activity>
</application>
</manifest>
The right instruction to call the activity is
intent. setClassName(BuildConfig.APPLICATION_ID, "com.example.dynamicfeature.MainActivityCalled");
It works, the activity gets called.
Note that BuildConfig.APPLICATION_ID is
com.example.mymodules
If this string is used in the dynamic modules too, you can make cross-calls:
-from one module to another
-from one module to the main app
but you do not want to use BuildConfig.APPLICATION_ID in modules because there it is a different value, so the main string value has to be put into a variable.
After migrating to Android Studio from Eclipse, I was struggling at best with it. Problem was that most guides and tutorials you could find are for Eclipse , but if you can find one for Android Studio, it is missing most important parts - implementing libraries or 3rd party code. After week of problems and errors here is a guide
Requirements: Google play services and Google Repostory (under Extras in SDK manager), BaseGameUtils
Firstly we need to add BaseGameUtils as Module:
then select Import Gradle Project and chose BaseGameUtil folder (do not copy BaseGameUtils in project before that step. Let Android Studio do that)
After gradle is done with syncing selefct Build > Make Module 'BaseGameUtils'
NOTE if u have uses-sdk:minSdkVersion error while build check this click here. Build :BaseGameUtils again after this
Last step for integranting BaseGameUtils is to include it into android module:
Sync project afterwards.
NOTE if you get uses-sdk:minSdkVersion error while build this will help - link
Now it's time to open your AndroidManifest file and include:
before application tag
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
NOTE: there is no need to add google play dependencies in android gradle script becouse it is already included in BaseGameUtils
in application, before activity
<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" />
Now you need to set app_id number in Srtings (android/res/values/Strings.xml)
<string name="app_id">928019648708</string>
Your app id is located in GooglePlay developer console under Game Services section (under game name)
For passing android native code to game code we will create ActionResolver interface in core module:
package com.mygame.test;
public interface ActionResolver {
public boolean getSignedInGPGS();
public void loginGPGS();
public void submitScoreGPGS(int score, String id);
public void unlockAchievementGPGS(String achievementId);
public void getLeaderboardGPGS();
public void getAchievementsGPGS();
}
Now we need to make changes in AndroidLauncher class (check imports if you have problems):
package com.mygame.test.android;
import android.os.Bundle;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.google.android.gms.games.Games;
import com.google.example.games.basegameutils.GameHelper;
import com.mygame.test.ActionResolver;
import com.mygame.test.MyGame;
public class AndroidLauncher extends AndroidApplication implements ActionResolver, GameHelper.GameHelperListener {
private GameHelper gameHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (gameHelper == null) {
gameHelper = new GameHelper(this, GameHelper.CLIENT_GAMES);
gameHelper.enableDebugLog(true);
}
gameHelper.setup(this);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
initialize(new MyGame(this), config);
}
#Override
public boolean getSignedInGPGS() {
return gameHelper.isSignedIn();
}
#Override
public void loginGPGS() {
if (!gameHelper.isSignedIn()) {
try {
runOnUiThread(new Runnable() {
public void run() {
gameHelper.beginUserInitiatedSignIn();
}
});
} catch (final Exception ex) {
Gdx.app.log("MainActivity", "Log in failed: " + ex.getMessage() + ".");
}
} else {
gameHelper.reconnectClient();
}
}
#Override
public void submitScoreGPGS(int score, String id) {
Games.Leaderboards.submitScore(gameHelper.getApiClient(), id, score);
}
#Override
public void unlockAchievementGPGS(String achievementId) {
Games.Achievements.unlock(gameHelper.getApiClient(), achievementId);
}
#Override
public void getLeaderboardGPGS() {
if (gameHelper.isSignedIn()) {
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(gameHelper.getApiClient(), "CgkI5MyZk4FbHAJQXQ"), 100);
} else if (!gameHelper.isConnecting()) {
loginGPGS();
}
}
#Override
public void getAchievementsGPGS() {
if (gameHelper.isSignedIn()) {
startActivityForResult(Games.Achievements.getAchievementsIntent(gameHelper.getApiClient()), 101);
} else if (!gameHelper.isConnecting()) {
loginGPGS();
}
}
#Override
public void onSignInFailed() {
gameHelper.getSignInError();
}
#Override
public void onSignInSucceeded() {
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
gameHelper.onActivityResult(requestCode, resultCode, data);
}
}
Create constructor in your main class (MyGame in this example):
public ActionResolver resolver;
public Base(ActionResolver ar) {
resolver = ar;
}
to connect with gplay services call:
if (!resolver.getSignedInGPGS())
resolver.loginGPGS();
unlock achievements and submit scores with:
if (resolver.getSignedInGPGS()){
if (currentScore == 0){
resolver.unlockAchievementGPGS("CgkI5MyZk4EbEAIQAg");
}
if (Cookie.bestScore >= 100){
resolver.unlockAchievementGPGS("CgkI5MyZk4EbEAIQAw");
}
resolver.submitScoreGPGS(Cookie.bestScore, "CgkI5MyZk4EbEAIQAQ");
}
note: use corresponding id valuses found in developer console for each achievement and for leaderbord
and call leaderboards and achievements with
resolver.getLeaderboardGPGS();
resolver.getAchievementsGPGS();
Lastly desktop, ios and html launcher can be resolved in the same way (example for desktop launcher)
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
ActionResolver resolver= new ActionResolver() {
#Override
public boolean getSignedInGPGS() {
return false;
}
#Override
public void loginGPGS() {
}
#Override
public void submitScoreGPGS(int score, String id) {
}
#Override
public void unlockAchievementGPGS(String achievementId) {
}
#Override
public void getLeaderboardGPGS() {
}
#Override
public void getAchievementsGPGS() {
}
};
new LwjglApplication(new MyGame(resolver), config);
}
I have a basic app for kids that allows them to click on icon to perform a youtube search (link to amazon app store).
Although I have done a lot of changes in the app, its removed from the Google Play store for "violation of the YouTube Terms of Service or YouTube API Terms of Service" (the full text is attached below).
I did a research here and it seems that my app dosen't have the problems that i have seen in other applications. the app dosen't have AD's and i think its not interfiring to the youtube Ad's and not playing videos in background.
In addition, I filed an appeal to Google Play. Their response was that my app streams copyrighted content from YouTube. I had a search for cartoons, so i removed it and resubmited and the app rejected again for the same reason.
when i asked for further assistance they answer: "Unfortunately, as much as we'd like to help, we aren't able to provide additional information for your inquiry".Very frustrating.
I'd appreciate your help. Perhaps i made a mistake in the code that implements the YoutubePlayer, Other ideas are welcome to.
the full Notification from Google Play:
This is a notification that your application, KidoTube, for package ID com.elelad.kidstube, has been removed from Google Play.
Please address the issue described below and submit a compliant update. Once approved, your application will again be available with all installs, ratings and reviews intact.
REASON FOR REMOVAL:Violation of section 4.4 of the Developer Distribution Agreement.
After a regular review, we have determined that your app downloads, monetizes, or otherwise accesses YouTube videos in violation of the YouTube Terms of Service or YouTube API Terms of Service. Accessing content, a product, or service in an unauthorized manner is a violation of the Developer Distribution Agreement, and is not allowed on Google Play.
All removals are tracked. Repeated removals will result in app suspension, at which point this app will count as a strike against the good standing of your developer account and no longer be available on Google Play.
This notification also serves as notice for other apps in your catalog. You can avoid future removals and/or app suspensions by immediately ensuring that no other apps in your catalog are in violation of (but not limited to) the above policy. Before publishing applications, please ensure your apps’ compliance with the Developer Distribution Agreement and Content Policy.
If you feel we have made this determination in error, you can visit this Google Play Help Center article.
The Google Play Team
My YoutubeActivity Class:
public class YoutubeActivity extends YouTubeBaseActivity implements YouTubePlayer.OnInitializedListener {
private final static String TAG = YoutubeActivity.class.getSimpleName();
YouTubePlayer player;
public static String YOUTUBE_VIDEO_ID = null;
LayoutInflater mLayoutInflater;
private FragmentActivity myContext;
public TextView textToast;
public View toastLayout;
ProgressBar cycleProgressBar;
Search search = new Search();
List<Video> mVideoList;
private static boolean initialize = false;
GetRandomInBackground getRandomInBackground;
YouTubePlayerView youTubePlayer;
ImageView waitLogo;
AnimationDrawable frameAnimation2;
ImageButton play;
public static void setYoutubeVideoId(String youtubeVideoId) {
YOUTUBE_VIDEO_ID = youtubeVideoId;
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}
}
#Override
public void onCreate(Bundle savedInstanseState) {
super.onCreate(savedInstanseState);
ContentResolver mContentResolver = getContentResolver();
setContentView(R.layout.youtube_player);
waitLogo = (ImageView) findViewById(R.id.player_logo);
play = (ImageButton) findViewById(R.id.play);
try {
startLogoAnimation();
}catch (Exception e){
waitLogo.setImageResource(R.mipmap.kidotube);
}
youTubePlayer = (YouTubePlayerView) findViewById(R.id.vYouTubePlayer);
if (Setting.isStartRandomVideo()) {
getRandomInBackground = new GetRandomInBackground();
getRandomInBackground.execute();
}
youTubePlayer.initialize(Search.getGoogleApiKey(), this);
youTubePlayer.setVisibility(View.INVISIBLE);
}
#Override
protected void onPause() {
super.onPause();
BaseActivity.myLifecycleHandler.onActivityPaused(this);
}
#Override
protected void onResume() {
super.onResume();
BaseActivity.myLifecycleHandler.onActivityResumed(this);
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider,
YouTubeInitializationResult result) {
Toast.makeText(this, "Cant initialize YouTube Player", Toast.LENGTH_LONG).show();
finish();
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer mplayer,
boolean wasRestored) {
this.player = mplayer;
player.setPlayerStyle(YouTubePlayer.PlayerStyle.CHROMELESS);
player.setPlayerStateChangeListener(playerStateChanageListener);
player.setPlaybackEventListener(playBackEvaentListener);
if (!Setting.isStartRandomVideo()) {
player.loadVideo(YOUTUBE_VIDEO_ID);
}
}
private YouTubePlayer.PlaybackEventListener playBackEvaentListener = new YouTubePlayer.PlaybackEventListener() {
public void onBuffering(boolean arg0) {
Log.v(TAG, "onBuffering");
}
#Override
public void onPaused() {
Log.v(TAG, "onPaused");
}
#Override
public void onPlaying() {
Log.v(TAG, "onPlaying");
}
#Override
public void onSeekTo(int arg0) {
Log.v(TAG, "onSeekTo");
}
#Override
public void onStopped() {
Log.v(TAG, "onStopped");
}
};
private YouTubePlayer.PlayerStateChangeListener playerStateChanageListener = new YouTubePlayer.PlayerStateChangeListener() {
#Override
public void onAdStarted() {
}
#Override
public void onError(YouTubePlayer.ErrorReason arg0) {
Log.v(TAG, "onError" );
Toast.makeText(YoutubeActivity.this, getString(R.string.Video_Error), Toast.LENGTH_LONG).show();
finish();
}
#Override
public void onLoaded(String arg0) {
Log.v(TAG, "onLoaded" + arg0);
}
#Override
public void onLoading() {
Log.v(TAG, "onLoading" );
}
#Override
public void onVideoEnded() {
Log.v(TAG, "onVideoEnded" );
finish();
}
#Override
public void onVideoStarted() {
Log.v(TAG, "onVideoStarted");
play.setVisibility(View.INVISIBLE);
waitLogo.setVisibility(View.INVISIBLE);
frameAnimation2.stop();
youTubePlayer.setVisibility(View.VISIBLE);
}
};
public class GetRandomInBackground extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
search.SearchNow(MainActivity.getSearchFor());
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
try {
if (search.getVideoList() == null || search.getVideoList().size() == 0) {
Toast.makeText(YoutubeActivity.this, getString(R.string.No_results_found), Toast.LENGTH_LONG).show();
Intent intent = new Intent(YoutubeActivity.this, MainActivity.class);
startActivity(intent);
} else {
mVideoList = search.getVideoList();
setYoutubeVideoId(search.playRand(mVideoList));
player.loadVideo(YOUTUBE_VIDEO_ID);
Search.setNumberOfVideosReturned(20);
}
}catch (Exception e){
finish();
}
}
}
public void startLogoAnimation(){
waitLogo.setBackgroundResource(R.drawable.wait_icon);
frameAnimation2 = (AnimationDrawable) waitLogo
.getBackground();
frameAnimation2.start();
}
public int animationDuration(AnimationDrawable animationDrawable){
int duration = 0;
int frames = animationDrawable.getNumberOfFrames();
for (int i = 0; i<frames; i++){
duration = duration + animationDrawable.getDuration(i);
}
return duration;
}
Thanks in advance!
well, it was one of my settings.
I made an option to click on icon and play a random video, apparently it's violation of the API terms.
When I removed the option the application is approved.
I hope this is the end..
I'm attempting to get Google Games to work with my application, but I'm having some issues. When I start my app, I call googleApiClient.connect(); on my onStart() method, along with some other code (posted below). Immediately when I start my app I get the log statement that onConnectionFailed was called and then the sign in process begins, the green fragment comes up and tells me to select my account. When I select my account, I get the log that is in onSignInFailed. I'm really confused what I'm doing wrong here. Any help would be greatly appreciated!
Here we go, I tried to only include the relevant bits:
public class SelectionScreen extends BaseGameActivity
implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient googleApiClient;
private boolean mResolvingConnectionFailure = false;
private boolean mAutoStartSignInflow = true;
private boolean mSignInClicked = false;
private static int RC_SIGN_IN = 9001;
private boolean mIntentInProgress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_selection_screen);
googleApiClient = new GoogleApiClient.Builder(this)
.addOnConnectionFailedListener(this).addConnectionCallbacks(this)
.addApi(Games.API).addScope(Games.SCOPE_GAMES).build();
}
#Override
protected void onStart() {
super.onStart();
googleApiClient.connect();
Log.d("Attempting to connect..", "");
}
#Override
protected void onStop() {
super.onStop();
googleApiClient.disconnect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d("Connection failed! ", ":-(");
if (!mIntentInProgress && connectionResult.hasResolution()) {
try {
mIntentInProgress = true;
startIntentSenderForResult(connectionResult.getResolution()
.getIntentSender(), RC_SIGN_IN, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
mIntentInProgress = false;
googleApiClient.connect();
}
}
if (mResolvingConnectionFailure) {
return;
}
if (mSignInClicked || mAutoStartSignInflow) {
mAutoStartSignInflow = false;
mSignInClicked = false;
mResolvingConnectionFailure = true;
if (!BaseGameUtils.resolveConnectionFailure(this,
googleApiClient, connectionResult,
RC_SIGN_IN, "Signing in -- other error")) {
mResolvingConnectionFailure = false;
}
}
//show sign in button
ft = fm.beginTransaction();
ft.replace(R.id.fragment_container, fragmentTwo);
ft.addToBackStack(null);
ft.commit();
}
#Override
public void onSignInButtonClicked(View view) {
googleApiClient.connect();
}
#Override
public void onSignInFailed() {
Log.d("sign in failed", "");
}
#Override
public void onSignInSucceeded() {
Log.d("sign in succeeded woo", "");
}
#Override
public void onActivityResult(int requestCode, int responseCode, Intent intent) {
super.onActivityResult( requestCode, responseCode, intent );
mHelper.onActivityResult( requestCode, responseCode, intent );
}
}
Is there some way I can get more detail about exactly what is causing the sign in error/connection error?
On the google play developer console it says my OAUTO 2.0 is fine, and I got the SHA thing from my keystore fine.. I'm sure I'm doing something retarded with my code, but I'm just not sure what. Any help would be appreciated, thanks!
edit Here are the metadata things of my manifest. Maybe I did these wrong? It looks correct from their guide.
<application>
//not showing all my activity stuff and application data, did I put the meta-data in the wrong place maybe?
<meta-data
android:name="com.google.android.gms.games.APP_ID"
//this is a number from my ids.xml file
android:value="#string/app_id" />
<meta-data
android:name="com.google.android.gms.version"
//generated by gradle, it finds the correct number (7327000)
android:value="#integer/google_play_services_version" />
</application>
Normally BaseGameActivity does all the heavy lifting for you so there's no need to do all the low level connection stuff in your custom Activity.
As stated here:
Subclasses only need to override the onSignInSucceeded and onSignInFailed abstract methods. To initiate the sign-in flow when the user clicks the sign-in button, subclasses should call beginUserInitiatedSignIn.
Also, are you sure you've set up Google Play Game Services using your local debug keystore?
I have been asking questions related to my Libgdx game Google play game services configuration error. Up-till now I have solved sign in errors but Now I am stuck at Unlock Achievements. So I am posting my code may Be some one can help me out then.
Here Is my ActionResolver Interface That I created In Core Libgdx project
package com.------.game;
public interface ActionResolver {
public boolean getSignedInGPGS();
public void loginGPGS();
public void submitScoreGPGS(int score);
public void unlockAchievementGPGS(String achievementId);
public void getLeaderboardGPGS();
public void getAchievementsGPGS();
public void onShowAchievementsRequested() ;
}
My AndroidLauncher class is
package com.------.game.android;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.games.Games;
import com.google.android.gms.plus.Plus;
import com.google.example.games.basegameutils.BaseGameUtils;
import com.google.example.games.basegameutils.GameHelper;
import com.google.example.games.basegameutils.GameHelper.GameHelperListener;
import com.-----.game.ActionResolver;
import com.-----.game.MainGame;
public class AndroidLauncher extends AndroidApplication implements
ActionResolver, GameHelperListener , GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener
{
private GameHelper gameHelper;
private GoogleApiClient client;
private Exception e;
final String TAG = "TanC";
private boolean mResolvingConnectionFailure = false;
// Has the user clicked the sign-in button?
private boolean mSignInClicked = false;
// Automatically start the sign-in flow when the Activity starts
private boolean mAutoStartSignInFlow = true;
// request codes we use when invoking an external activity
// private static final int RC_RESOLVE = 5000;
private static final int RC_UNUSED = 5001;
private static final int RC_SIGN_IN = 9001;
// tag for debug logging
final boolean ENABLE_DEBUG = true;
// playing on hard mode?
boolean mHardMode = false;
private int Score;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Score= 100;
client = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
.addApi(Games.API).addScope(Games.SCOPE_GAMES)
.build();
GameHelper.GameHelperListener gameHelperListener = new GameHelper.GameHelperListener() {
#Override
public void onSignInFailed() {
Log.i("Game Helper", "Sign in failed");
}
#Override
public void onSignInSucceeded() {
Log.i("Game Helper", "Sign in succeeded");
}
};
if (gameHelper == null) {
gameHelper = new GameHelper(this, GameHelper.CLIENT_GAMES);
gameHelper.enableDebugLog(true);
}
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
initialize(new MainGame(this), config); // or initialize (game,
// config);
// gameHelper.setPlusApiOptions(PlusOptions.builder().build());
// no title is needed
gameHelper.setup(gameHelperListener );
// gameHelper.setup(gameHelperListener );
}
#Override
public void onStart() {
super.onStart();
gameHelper.onStart(this);
client.connect();
}
#Override
public void onStop() {
super.onStop();
// ...
gameHelper.onStop();
if (client.isConnected()) {
client.disconnect();
}
}
#Override
public void loginGPGS() {
try {
runOnUiThread(new Runnable() {
public void run() {
gameHelper.beginUserInitiatedSignIn();
}
});
} catch (final Exception ex) {
e.printStackTrace ();
}
}
#Override
public void unlockAchievementGPGS(String achievementId) {
if ( getSignedInGPGS()) {
if(Score>=100){
unlockAchievementGPGS("ABC-------");
}
Games.Achievements.unlock(client, getString(R.string.achievement_Trekker));
}
}
#Override
public void getLeaderboardGPGS() {
}
#Override
public void getAchievementsGPGS() {
if (gameHelper.isSignedIn()) {
startActivityForResult(
Games.Achievements.getAchievementsIntent(gameHelper
.getApiClient()), 101);
} else if (!gameHelper.isConnecting()) {
loginGPGS();
}
}
#Override
public void submitScoreGPGS( int score) {
submitScoreGPGS(Score);
// game.actionResolver.submitScoreGPGS(world.score);
}
#Override
public void onActivityResult(int request, int response, Intent data) {
super.onActivityResult(request, response, data);
gameHelper.onActivityResult(request, response, data);
}
#Override
public boolean getSignedInGPGS() {
return gameHelper.isSignedIn();
}
private boolean isSignedIn() {
return (client!= null && client.isConnected());
}
#Override
public void onShowAchievementsRequested() {
if (isSignedIn()) {
startActivityForResult(Games.Achievements.getAchievementsIntent(client),
RC_UNUSED);
} else {
BaseGameUtils.makeSimpleDialog(this, getString(R.string.achievement_Trekker)).show();
}
}
#Override
public void onSignInFailed() {
}
#Override
public void onSignInSucceeded() {
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
Log.d(TAG, "onConnectionFailed(): attempting to resolve");
/* if (mResolvingConnectionFailure) {
Log.d(TAG, "onConnectionFailed(): already resolving");
return;
}
if (mSignInClicked || mAutoStartSignInFlow) {
mAutoStartSignInFlow = false;
mSignInClicked = false;
mResolvingConnectionFailure = true;
if (!BaseGameUtils.resolveConnectionFailure(this, client, connectionResult,
RC_SIGN_IN, getString(R.string.unknown_error))) {
mResolvingConnectionFailure = false;
}*/
}
#Override
public void onConnected(Bundle arg0) {
Log.i("Google API", "onConnected(): connected to Google APIs");
}
#Override
public void onConnectionSuspended(int arg0) {
Log.d(TAG, "onConnectionSuspended(): attempting to connect");
client.connect();
}
}
This score int that has a value of 100 I just tried to test if it helps to unlock achievement.
My MainGame class in Core project is
package com.----------.game;
import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.-------.helpers.AssetLoader;
import com.------.screens.FirstSplash;
public class MainGame extends Game {
SpriteBatch batch;
Texture img;
public ActionResolver actionResolver;
Game game;
public MainGame(ActionResolver actionresolver) {
this.actionResolver = actionresolver;
}
#Override
public void create() {
Gdx.app.log("Game", "created");
AssetLoader.load();
setScreen(new FirstSplash(this));
}
public void show() {
Gdx.app.log("my Splash Screen", "show called");
if (Gdx.app.getType() == ApplicationType.Android) {
actionResolver.getSignedInGPGS();
actionResolver.submitScoreGPGS(110);
actionResolver.unlockAchievementGPGS("ABC-----");
} else {
actionResolver.loginGPGS();
}
}
#Override
public void dispose() {
super.dispose();
AssetLoader.dispose();
}
}
My Android Manifest File is
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.--------.game.android"
android:versionCode="2"
android:versionName="1.1" >
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="20" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#drawable/smallicon"
android:label="#string/app_name"
android:theme="#style/GdxTheme"
android:name="com.---------.game.android.MyApplication">
<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="com.outofboxapps.game.android.AndroidLauncher"
android:label="#string/app_name"
android:screenOrientation="landscape"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
My Strings File in Android/Res folder has this
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">My Game</string>
<string name="app_id">------------</string> // has my app id
</resources>
My Logcat says this when I run my app in Debug Mode(Note: I have already configured Google play game services on Developer console| My game is already published without Game services in First Version so to test Game services I have published my Game services in Alpha. I have successfully added testers. I am able to sign in with test account. I also have Dubug plus release certificates Client ID)
03-11 10:28:49.823: I/my Spash Screen(16750): constructor called
03-11 10:28:49.829: I/my Splash Screen(16750): hide called
03-11 10:28:49.830: I/my Splash Screen(16750): rendered 2 times.
03-11 10:28:49.830: I/my Splash Screen(16750): show called
03-11 10:28:50.030: D/GameHelper(16750): GameHelper: onConnected: connected!
03-11 10:28:50.038: D/GameHelper(16750): GameHelper: succeedSignIn
03-11 10:28:50.044: D/GameHelper(16750): GameHelper: Notifying LISTENER of sign-in SUCCESS
03-11 10:28:52.837: I/my Spash Screen(16750): constructor called
03-11 10:28:52.869: I/my Splash Screen(16750): hide called
03-11 10:28:52.869: I/my Splash Screen(16750): rendered 180 times.
03-11 10:28:57.361: I/GameScreen(16750): show called
03-11 10:28:57.361: I/GameScreen(16750): resizing
Now I dont get it. when I am SUCCESSFULLY CONNECTED why i cant do anything else in game services. I just have achievements that I need to unlock on a particular score.
Using all LIBGDX game tutorials, Google Type a number and trival exmaple and tutorial I feel hopeless now that I cant configure these game services at all.
I was also sending my scores at game over from gamescreen class but removed it now because it simply generate Null pointer exception on Sign in(to google game services). I can post that code as well
if (Gameover ----) {
if ((game.actionResolver.getSignedInGPGS())) { // My app crashes at this point ton check Sign in by giving Null pointer exception
game.actionResolver.submitScoreGPGS(AssetLoader.getScore);
if (AssetLoader.getScore >= 2500) game.actionResolver.unlockAchievementGPGS("-----"); // my id is here
}
}
KINDLY ANYBODY WHO HAS DONE THIS SUCCESSFULLY. hELP ME OUT.
Take a look at your loginGPGS() method in your launcher class...You can successfully connect because loginGPGS is run on the ui thread....Try accessing GPGS on the ui thread because it needs to be run in the context of your Main activity....This is how I access mine:
#Override
public void getLeaderboardGPGS() {
try {
runOnUiThread(new Runnable() {
public void run() {
if (gameHelper.isSignedIn()) {
startActivityForResult(
Games.Leaderboards.getLeaderboardIntent(
gameHelper.getApiClient(),
"XXXXXXXXXX-XXX-XXX"), 100);
} else if (!gameHelper.isConnecting()) {
loginGPGS();
}
}
});
} catch (final Exception ex) {
}
}
#Override
public void sendScoreGPGS() {
try {
runOnUiThread(new Runnable() {
public void run() {
if (gameHelper.isSignedIn()) {
startActivityForResult(
Games.Leaderboards.submitScore(gameHelper.getApiClient(),
"YOUR-GPGS-HASH", score);
} else if (!gameHelper.isConnecting()) {
loginGPGS();
}
}
});
} catch (final Exception ex) {
}
}