I'm trying to implement the saved games codes, I can save and load without problems, all the data is OK. But I when I connect with Google, the code connect with a default account. I try to use account picker and use the returned mail but the account was the same, same data. I need select the account or my code is useless.
This is my connect code:
public static void conectarGoogle(final FragmentActivity a) {
GoogleApiClient.ConnectionCallbacks connectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG,"conected");
}
#Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
};
GoogleApiClient.OnConnectionFailedListener cfl = new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d(TAG,"failed="+connectionResult.toString());
mIsResolving = BaseGameUtils.resolveConnectionFailure(a, mGoogleApiClient, connectionResult, RC_SIGN_IN, a.getString(R.string.signin_other_error));
}
};
mGoogleApiClient = new GoogleApiClient.Builder(a)
.addConnectionCallbacks(connectionCallbacks)
.addOnConnectionFailedListener(cfl)
.addApi(Games.API)
.addScope(Games.SCOPE_GAMES)
.addScope(Drive.SCOPE_APPFOLDER)
.setViewForPopups(a.findViewById(android.R.id.content))
.build();
mGoogleApiClient.connect();
}
public static void desconectarGoogle(){
if(mGoogleApiClient!=null && isSignedIn()) {
mGoogleApiClient.disconnect();
}
}
I need help for this problem. I use this code in mainactivity and preferencesactivity and cant select the account for save the progress.
The default account use the marchinglord2524 name.
The Games.API dont left add Auth.GOOGLE_SIGN_IN_API.
(Posted on behalf of the OP).
I don't know why, but I have in my device a default user, I clear the data on my Google Play Services and now I use my user: saved games documentation.
Related
I was using GoogleApiClient to use location information while using Google Maps.
However, it is now deprecated. I looked it up in the official document and found that you should use GoogleApi<O>.
I tried to create an object, but I don't know how to work on it.
I need your help.
GoogleApiClient - Deprecated
googleApiClientBuilder = new GoogleApiClient.Builder(mContext);
googleApiClientBuilder.addApi(LocationServices.API);
googleApiClientBuilder.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
createLocationRequest(); // my work
createLocationBuild(); // my work
createLocationSetting(); // my work
}
#Override
public void onConnectionSuspended(int i) {}
});
My working GoogleApi<o>...
GoogleApi<Api.ApiOptions.NoOptions> googleApi = new GoogleApi<>(mContext, LocationServices.API, Api.ApiOptions.NO_OPTIONS, GoogleApi.Settings.DEFAULT_SETTINGS);
I have an activity that extends a base class called LocationAwareActivity all this LocationAwareActivity activity does is creates a location service client
LocationServices.getFusedLocationProviderClient and listens to
location updates.
Source for this activity is here
https://github.com/snijsure/MultiActivity/blob/master/app/src/main/java/com/example/subodhnijsure/multiactivity/LocationAwareActivity.java
And when activity is destroyed it calls removeLocationUpdates . What I am finding is
removeLocationUpdate returns a task that always returns not-successful
More concerning is because location activities is not removed, the activity is not getting being garbage collected.
- So if I start the any activity that inherits from LocationAwareActivity that activity always stays on heap.
So the question is what is the correct way to stop receiving location updates thus allowing activity to be garbage collected.
Entire source for this project can be accessed here - https://github.com/snijsure/MultiActivity
In removeLocationUpdates you should pass locationCallback, current implementation is wrong.
Still, there is chance of memory leak somewhere else. You should try integrating Leakcanary in your app and it can give you reference tree and will tell you which field or listener is causing this memory leak.
You can refer one of my only blog post here
public void stopLocationUpdates() {
if (locationProviderClient != null) {
try {
final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
if (voidTask.isSuccessful()) {
Log.d(TAG,"StopLocation updates successful! ");
} else {
Log.d(TAG,"StopLocation updates unsuccessful! " + voidTask.toString());
}
}
catch (SecurityException exp) {
Log.d(TAG, " Security exception while removeLocationUpdates");
}
}
}
Hi #Subodh Nijsure Please check below code and paste into your code and after checked it:
final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
voidTask.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.e(TAG, "addOnCompleteListener: "+task.isComplete());
}
});
voidTask.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.e(TAG, "addOnSuccessListener: " );
}
});
voidTask.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "addOnFailureListener: ");
}
});
I think voidTask.isSuccessful() this method is not working when you put this listener at that time it working fine and i also see into memory it's release all memory when come to previous Activity.
And when you are redirecting to any activity then please stopLocationUpdates() called once into onPause() and remove from other method like onDestroy(),onStop() because it stop once so why should we call multiple time.
Hope this helps you.
By looking at the code in the repository I discovered some issues in your design that maybe cause the leaking of your Activity.
1) You are using two different LocationCallbacks. One in the start and one in the stop method, but you should actually use the same. So one time instantiating it would be sufficient and would lead probably also to a successful result of your Task when removing the LocationCallback.
2) Since your instantiating the LocationCallback twice with an Anonymous Class you are keeping a non-static reference of an inner class even if you finish the containing class and this causes your Memory Leak. You can read more about this here.
3) IMHO it is better to use a separate manager class for handling your location requests than abstracting an Activity.
That said here is my...
Solution
GpsManager.java
public class GpsManager extends LocationCallback {
private FusedLocationProviderClient client;
private Callback callback;
public interface Callback {
void onLocationResult(LocationResult locationResult);
}
public boolean start(Context context, Callback callback) {
this.callback = callback;
client = LocationServices.getFusedLocationProviderClient(context);
if (!checkLocationPermission(context)) return false;
client.requestLocationUpdates(getLocationRequest(), this, null);
return true;
}
public void stop() {
client.removeLocationUpdates(this);
}
#Override
public void onLocationResult(LocationResult locationResult) {
callback.onLocationResult(locationResult);
}
private boolean checkLocationPermission(Context context) {
int permissionCheck = ContextCompat.checkSelfPermission(
context, android.Manifest.permission.ACCESS_FINE_LOCATION);
return permissionCheck == PackageManager.PERMISSION_GRANTED;
}
private LocationRequest getLocationRequest() {
return LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(30_000L)
.setFastestInterval(20_000L);
}
}
and calling this from your Activity like this
YourActivity.java
public class MapsActivity extends AppCompatActivity implements GpsManager.Callback {
private static final int PERMISSION_REQUEST_FINE_LOCATION = 1;
private GpsManager mGpsManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mGpsManager = new GpsManager(getApplicationContext(), this);
// check if user gave permissions, otherwise ask via dialog
if (!checkPermission()) {
getLocationPermissions();
return;
}
mGpsManager.start();
...
}
#Override
protected void onStop() {
super.onStop();
mGpsManager.stop();
}
#Override
public void onLocationResult(LocationResult locationResult) {
// do something with the locationResult
}
// CHECK PERMISSIONS PART
private boolean checkPermission() {
return isGranted(ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION)) &&
isGranted(ActivityCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION));
}
#TargetApi(Build.VERSION_CODES.M)
private void getLocationPermissions() {
requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSION_REQUEST_FINE_LOCATION);
}
#Override
public void onRequestPermissionsResult(int code, #Nullable String permissions[], #Nullable int[] results) {
switch (code) {
case PERMISSION_REQUEST_FINE_LOCATION:
if (isPermissionGranted(results)) {
getLocationRequest();
}
}
}
private boolean isPermissionGranted(int[] results) {
return results != null && results.length > 0 && isGranted(results[0]);
}
private boolean isGranted(int permission) {
return permission == PackageManager.PERMISSION_GRANTED;
}
}
This is just a guess because I didn't try your code but the solution should help you anyways. Please correct me if I'm wrong ;)
The reason why the Task object returns false is in your stopLocationUpdates method, you are again creating a local **LocationCallback** reference and then using this reference to as an argument in locationProviderClient.removeLocationUpdates(cL);
where your local LocationCallBack is never present in the locationProviderClient
So what you have to do is , instead of creating another LocationCallBack object ,you have to pass the same global object which you are instantiating in your startLocationUpdates method
your code should be like this
final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
I'm working on an App where i want to stream a specific video, which is located on my mobile device. I want to stream this video with the help of ChromeCast to a projector. I've done the Google Chromecast Tutorials (https://codelabs.developers.google.com/codelabs/cast-videos-android/#0 for example) and already looked for an answer to my Question but there wasn't the perfect answer to solve my problem in my opinion.
There are a few solutions in other coding languages but not especially for java.
My problem with the Google Cast API is: I want to select my ChromeCast without pressing the Cast Button in the OptionMenu, which appears to select one of the ChromeCasts in the Network.
I just found out, that the setRouteSelector-Methode from the class CastButtonFactory is a part to select the Device. But i can't find out, how to select the device automatically.
Here is my Code where the CastButton appears (created in the OnCreateOptionsMenu-Method)(It's just the Code to Connect to the ChromeCast. I didn't implement the Code for selecting and streaming the video yet):
Can anyone help me?
Code:
public class MainActivity extends AppCompatActivity {
private CastSession mCastSession;
private CastContext mCastContext;
private SessionManager mSessionManager;
private final SessionManagerListener mSessionManagerListener = new SessionManagerListenerImpl();
private class SessionManagerListenerImpl implements SessionManagerListener{
#Override
public void onSessionStarting(Session session) {}
#Override
public void onSessionStarted(Session session, String sessionId) {
invalidateOptionsMenu();
}
#Override
public void onSessionStartFailed(Session session, int i) {}
#Override
public void onSessionEnding(Session session) {}
#Override
public void onSessionEnded(Session session, int error) {
finish();
}
#Override
public void onSessionResuming(Session session, String s) {}
#Override
public void onSessionResumed(Session session, boolean wasSuspended) {
invalidateOptionsMenu();
}
#Override
public void onSessionResumeFailed(Session session, int i) {}
#Override
public void onSessionSuspended(Session session, int i) {}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCastContext = CastContext.getSharedInstance(this);
mCastContext.registerLifecycleCallbacksBeforeIceCreamSandwich(this, savedInstanceState);
mSessionManager = CastContext.getSharedInstance(this).getSessionManager();
}
#Override
public void onResume(){
mCastSession = mCastContext.getSessionManager().getCurrentCastSession();
mSessionManager.addSessionManagerListener(mSessionManagerListener);
super.onResume();
}
#Override
public void onPause(){
super.onPause();
mSessionManager.removeSessionManagerListener(mSessionManagerListener);
mCastSession = null;
}
#Override
public void onStart(){
super.onStart();
}
#Override public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu, menu);
CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
menu,
R.id.media_route_menu_item);
return true;
}}
This is possible with SDK v2. Check out the source code for MediaRouteChooserDialogFragment, the UI element that lets users select a Cast device. You'll want to create a MediaRouter.Callback, and override onRouteAdded(MediaRouter router, MediaRouter.RouteInfo newRoute). If the new route is not the default route, select it with mMediaRouter.selectRoute(newRoute). This will connect you to the receiver device without any user interaction.
This should work for testing, but please don't do this in a production app. #AliNaddaf correctly notes this is against the UX guidelines and Google Cast terms of service (you can imagine the potential for abuse if apps are permitted to start casting without the user's consent).
I use Firebase to handle the Auth topic of my Android app.
I also save a user profile on Firebase, that contain user id and extra options that user can update in the android app.
At startup, the app check the auth, and auth. It reload the user profile (on Firebase) to then update my userInstance on the app.
Firebase is set as offline capable at app level.
The userInstance POJO is sync with Firebase at log and stop to be sync at unlog.
I have a special parameter, in my user profile that I can change (as an admin).
Every-time I update it on the Firebase console, it is replaced by the previous value when the app start again.
How can this happen ?
BTW :
1/ Based on which mechanism are the data merged, if multiple client have different local values ?
Here is simpler code, where I tried to reproduce the error. :
MyApplication.java
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Firebase.setAndroidContext(this);
Firebase.getDefaultConfig().setLogLevel(Logger.Level.DEBUG);
Firebase.getDefaultConfig().setPersistenceEnabled(true);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://millezim-test.firebaseIO.com").child("user");
ref.keepSynced(true);
Button br = (Button) findViewById(R.id.b_read);
Button bs = (Button) findViewById(R.id.b_save);
final TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
br.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
if (u != null)
tv_r.setText(String.valueOf(u.getAge()));
else
tv_r.setText("Bad Value");
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
});
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
saveUser();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
public void saveUser() {
ref.setValue(user);
}
}
If you just change a value in the app, then the counter inc until the app stop : this is normal. But what is strand is the age pass from old to new then to old cyclically without stopping.
And I feel that behavior in my app, without the cyclic, as I do not have a counter, but I cannot change a parameter in the admin client, I always get back the previous value stored in the mobile.
I just Auth, then I update my UserInstance with AuthData + the User fetch from Firebase (probably the cached data), and then I save back the updated User under Firebase (As I may got new AuthData, and I normally get the latest User from Firebase)
2/ In this simple example, I saw that if I read the value at start, it fetch the data cached in the app. How can I force having online data ?
The problem comes from the fact that you're using disk persistence with a single-value event listener. When you do:
ref.addListenerForSingleValueEvent(new ValueEventListener() {...
You're asking for a single value of that location (the user in your case). If Firebase has a value for that location in its local cache, it will fire for that value straight away.
The best way to solve this is to not use a single-value listener, but instead use a regular event listener. That way you will get two events: one for the cached version and one for the version that comes back from the server (if it is different).
The only alternative is to not use Firebase's disk persistence. Without that, there won't be a local cache for the data to be read from upon a restart.
There were a few discussions about this combination on the Firebase mailing list. Here's one: https://groups.google.com/forum/#!msg/firebase-talk/ptTtEyBDKls/XbNKD_K8CQAJ
After digesting a bit, my current strategy is to use Firebase for my data persistance, and not use anymore my own objects. (Before I had to sync UI, my data, the firebase cache, and the server data)
So now, I use
use disk caching
use onValueEventListener
keep update data (only to be read with component that need sync data)
trigger event that update UI (for component that can accept async data)
define some specific setter, that update data on Firebase (not anymore at app level)
It does means, that when I update a data, it goes to the server (or Firebase caching layer) until it goes back to the UI. As firebase handle this caching, if fast this is fast enough, and this is Firebase that deal with network sync.
To bring the (1) solution from #frank-van-puffelen into code :
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://test.firebaseIO.com").child("user");
ref.keepSynced(true);
Button br = (Button) findViewById(R.id.b_read);
Button bs = (Button) findViewById(R.id.b_save);
final TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
br.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
if (u != null)
tv_r.setText(String.valueOf(u.getAge()));
else
tv_r.setText("Bad Value");
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
});
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
saveUser();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
public void saveUser() {
ref.setValue(user);
}
}
However, this change nothing, even worst. Now it seems that every value set, stay as a ghost value (hold by client/server request), and the value toggling can be seen with every values set !
EDIT
The following code worked out !
Having a normal ValueListener, that you stopped before saving again a value, and you enable back when save is completed ! (Ok I was thinking this may be done in the Firebase Framework).
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
private ValueEventListener theListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://test.firebaseIO.com").child("user");
ref.keepSynced(false);
Button bs = (Button) findViewById(R.id.b_save);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
theListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
updateUI(u);
saveUser();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
};
ref.addValueEventListener(theListener);
}
public void saveUser() {
ref.removeEventListener(theListener);
ref.setValue(user, new Firebase.CompletionListener() {
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
ref.addValueEventListener(theListener);
}
});
}
public void updateUI(User user) {
TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
if (user != null)
tv_r.setText(String.valueOf(user.getAge()));
else
tv_r.setText("Bad Value");
}
}
EDIT
However this do not allow to change a value on the admin page. The age value is set and then remain back to the one that is save on the mobile.
So I imaging then the only solution is to solve at system level. DO NOT USE VALUELISTENER FOR VALUE THAT AN APP CAN SAVE AND THAT CAN BE SAVED BY THIRD PARTY APP. Please advise/correct this assumption !
I am developing an app related to Google map. I have done following steps successfully.
Created API key to access Google Map
Added Google Play Services Library in my app
Added required permissions
Added map in my activity with SupportMapFragment
Added a separate class MyMap.java to manipulate the map
Passed tow parameters to this class - Context of main activity and object of GoogleMap
Turned Wi-Fi and GPS on and ran the app
After this I am getting map with nice look and controls.
MyMap.java
public class MyMap implements ConnectionCallbacks, OnConnectionFailedListener {
private Context context;
private GoogleMap map;
private GoogleApiClient client = null;
public MyMap(Context context, GoogleMap map) {
this.context = context;
this.map = map;
client = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
}
#Override
public void onConnected(Bundle arg0) {
Toast.makeText(context, "Connected", 1).show();
Location mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(client);
if (mLastLocation != null) {
Toast.makeText(
context,
String.valueOf(mLastLocation.getLatitude()) + ","
+ String.valueOf(mLastLocation.getLongitude()), 1)
.show();
}
}
#Override
public void onConnectionSuspended(int arg0) {
// TODO Auto-generated method stub
}
}
Problem
In the above class I want to toast the current location. But it is not toasting anything. At least I need to see a toast saying "connected" on onConnected
event. Is there something wrong in my implementation?
Thanks in advance.
You seemingly never connect your client so it would be a real suprise if onConnected was called :)
You create your client with
client = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
but for the client to do something you have to add:
client.connect();
getLastLocation() is going to give location only once. To get periodic location updates, you need to override onLocationChanged() method. You can get this Link
Best way that I found is simple implement you activity like so:
public class MapActivity extends Activity implements GoogleMap.OnMyLocationChangeListener
and override method
#Override
public void onMyLocationChange(Location location) {
mMap.addMarker(new MarkerOptions().position(location).icon(
BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
}
And don't forget about mMap.setMyLocationEnabled(true); and mMap.setOnMyLocationChangeListener(this); in map init method
That's all!
Also, you can check is map available like here:
public boolean checkMapsAvailable() {
int isAvailable = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (isAvailable == ConnectionResult.SUCCESS) {
return true;
} else if (GooglePlayServicesUtil.isUserRecoverableError(isAvailable)) {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(isAvailable, this, 9001);
dialog.show();
} else {
Constants.showToast(Constants.ALERT_GOOGLEPLAY_CONNECTION);
}
return false;
}
Hope this helps.