I am writing an android application to get the Facebook user albums and photos and display in my Android application.
I have created a Facebook App with APP_ID 281846961912565.
While creating the Facebook instance, I am passing this id as follows
facebook = new Facebook(APP_ID);
Using this instance, I am able to login to my FB account post on messages on facebook wall programatically.
After logging in, I get an access_token.
I'm using the access token to get the album ids using facebook.request("https://graph.facebook.com/me/albums?access_token="+facebook.getAccessToken());
Now I get {"error":{"message":"Malformed access token ACCESSTOKENACCESSTOKEN?access_token=ACCESSTOKENACCESSTOKEN","type":"OAuthException","code":190}}
Can any of you please help me resolve this issue and point out what i am doing wrong.
My code is as follows:
private static final String[] PERMISSIONS = new String[] { "publish_stream","user_photos" };
public boolean saveCredentials(Facebook facebook) {
Editor editor = getApplicationContext().getSharedPreferences(KEY,
Context.MODE_PRIVATE).edit();
editor.putString(TOKEN, facebook.getAccessToken());
editor.putLong(EXPIRES, facebook.getAccessExpires());
return editor.commit();
}
public boolean restoreCredentials(Facebook facebook) {
SharedPreferences sharedPreferences = getApplicationContext()
.getSharedPreferences(KEY, Context.MODE_PRIVATE);
facebook.setAccessToken(sharedPreferences.getString(TOKEN, null));
facebook.setAccessExpires(sharedPreferences.getLong(EXPIRES, 0));
return facebook.isSessionValid();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
facebook = new Facebook(APP_ID);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.facebook_dialog);
String facebookMessage = getIntent().getStringExtra("facebookMessage");
if (facebookMessage == null) {
facebookMessage = "Test wall post";
}
messageToPost = facebookMessage;
}
R.layout.facebook_dialog is the dialog which pops up asking if a message should be shared on facebook or not. If yes the following method is called.
public void share(View button) {
if (!facebook.isSessionValid()) {
loginAndPostToWall();
} else {
postToWall(messageToPost);
}
}
public void loginAndPostToWall() {
facebook.authorize(this, PERMISSIONS, Facebook.FORCE_DIALOG_AUTH,
new LoginDialogListener());
}
class LoginDialogListener implements DialogListener {
public void onComplete(Bundle values) {
saveCredentials(facebook);
if (messageToPost != null) {
postToWall(messageToPost);
}
}
public void onFacebookError(FacebookError error) {
showToast("Authentication with Facebook failed!");
finish();
}
public void onError(DialogError error) {
showToast("Authentication with Facebook failed!");
finish();
}
public void onCancel() {
showToast("Authentication with Facebook cancelled!");
finish();
}
}
public void postToWall(String message) {
Bundle parameters = new Bundle();
parameters.putString("message", message);
parameters.putString("description", "topic share");
try {
facebook.request("me");
String response = facebook.request("me/feed", parameters, "POST");
Log.d("Tests", "got response: " + response);
if (response == null || response.equals("")
|| response.equals("false")) {
showToast("Blank response.");
} else {
showToast("Message posted to your facebook wall!");
}
getImagesFromUserAlbum();
finish();
} catch (Exception e) {
showToast("Failed to post to wall!");
e.printStackTrace();
finish();
}
}
Later when I do a `private void getImagesFromUserAlbum() {
facebook.getAccessToken();
JSONArray albumss = null;
String response = null;
try {
response = facebook.request("me/albums");
// `
I get the error
{"error":{"message":"Malformed access token ACCESSTOKEN?access_token=ACCESSTOKEN","type":"OAuthException","code":190}}
Thanks for your help.
The code above is now the working copy. Thanks to Bartek.
If you look at the Errors page in the documentation you will see that when you get error 190 you should authorise/reauthorise the user.
I suspect that this happened to you because you first logged in, then added the permissions to access the albums to your application BUT did not log out and log back in. Hence, you need to obtain a new access token which will grant the new permissions to your application.
Please check is there &expires in your access token if yes then remove it because it is not part of access_token and try after that.
Related
I'm creating my splash screen for app. While loading it executes 4 methods. First one checks if Internet permission is granted, second one sends request to API to check if it is Online, third one is getting Token from Firebase and the fourth one is checking if user is already logged-in. I'm doing it using 4 threads. Each method in case of error sets the flag as false. Then when all the threads end their work (I used .join()) The last method checks the state of flag and launch new activity or just display Error and try everything once again.
The problem I have is that I'm getting the view after all the threads finish their work. For example I have black screen, then message ("Error occured") and only after that I can see UI. But on Error the UI is refreshed, so one more time I have black screen, then result and UI for 1sec until another restart.
My question is, can I in some way stop these Threads until my UI is ready ?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
setContentView(R.layout.activity_splash);
checkProgress = findViewById(R.id.checkProgressText);
auth = FirebaseAuth.getInstance();
tokenUtils = new TokenUtils();
requestQueue = Volley.newRequestQueue(getApplicationContext());
animatedCircleLoadingView = findViewById(R.id.circle_loading_view);
//starting the animation
startLoading();
Thread[] checkers = new Thread[4];
checkers[0] = new Thread(this::checkInternetPermissions);
checkers[1] = new Thread(this::checkConnection);
checkers[2] = new Thread(this::getUserAuth);
checkers[3] = new Thread(this::getUserToken);
for (Thread t : checkers) {
try {
t.start();
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
changeActivity();
}
Check internet permission method:
private void checkInternetPermissions() {
checkProgress.setText(getString(R.string.check_internet_permissions_text));
if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET)
!= PackageManager.PERMISSION_GRANTED)
requestPermissions(new String[]{Manifest.permission.INTERNET}, 1);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode != 1) {
connectionFlag = false;
}
}
Check connection method:
private void checkConnection() {
checkProgress.setText(getString(R.string.checking_api_connection));
RequestFuture<String> requestFuture = RequestFuture.newFuture();
StringRequest request = new StringRequest
(Request.Method.GET, API_CHECK,
requestFuture,
requestFuture);
requestQueue.add(request);
String response = null;
try {
response = requestFuture.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
this.connectionFlag = false;
}
if (!Objects.equals(response, "ok"))
this.connectionFlag = false;
}
Get user token method:
private void getUserToken() {
checkProgress.setText(getString(R.string.getting_user_auth_token));
String token = null;
try {
token = tokenUtils.getFirebaseToken();
} catch (ExecutionException | InterruptedException e) {
this.connectionFlag = false;
}
if (Objects.isNull(token) || Objects.requireNonNull(token).isEmpty())
this.connectionFlag = false;
}
And finally get user auth method:
private void getUserAuth() {
checkProgress.setText(getString(R.string.checking_user_auth));
authStateListener = firebaseAuth -> {
firebaseUser = firebaseAuth.getCurrentUser();
if (Objects.isNull(firebaseUser) || Objects.requireNonNull(firebaseUser.getEmail()).isEmpty()) {
this.authFlag = false;
}
};
}
Last method which handle the states of flags:
private void changeActivity() {
checkProgress.setText(getString(R.string.finalizing_text_progress));
if (connectionFlag && authFlag) {
startActivity(new Intent(SplashActivity.this, MapActivity.class));
} else if (!connectionFlag) {
Toast.makeText(getApplicationContext(), "Error occurred.", Toast.LENGTH_LONG).show();
finish();
startActivity(getIntent());
} else {
startActivity(new Intent(SplashActivity.this, LoginActivity.class));
}
}
Yes, You can try it with handler thread with some delay then it will work fine or you can start your thread on onResume() method at the time of onResume your view will have been created
I think, your way wrong. Because, API request working on asynchronous. Your app should run like this;
Check Internet connection.
API Request.
Get token in API Request onSuccess method.
Get User Auth.
I think, you shouldn't use Thread.
Basically I'm using the facebook sdk in my android app. However, on my scoreboard activity i need to use the access token to get my results for my high scores.
However everytime I try to use
accessToken = AccessToken.getCurrentAccessToken();
It's either null or my app crashes because it's a null pointer error.
java.lang.RuntimeException: Unable to start activity ComponentInfo{wmrapplications.plankoff/wmrapplications.plankoff.ScoreBoard}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.facebook.AccessToken.getToken()' on a null object reference
What I need it to do is retrieve the current login for the current login session.
I tried this using an "isloggedin" method.
public boolean isLoggedIn() {
accessToken = AccessToken.getCurrentAccessToken();
if (accessToken == null) {
Toast.makeText(getApplicationContext(), "no access token", Toast.LENGTH_LONG).show();
accessTokenTracker = new AccessTokenTracker() {
#Override
protected void onCurrentAccessTokenChanged(AccessToken oldAccessToken, AccessToken currentAccessToken) {
// fetchUserInfo();
}
};
callbackManager = CallbackManager.Factory.create();
} else {
Toast.makeText(getApplicationContext(), " access token", Toast.LENGTH_LONG).show();
Token = accessToken.getToken().toString();
}
return accessToken != null;
}
along with a fetchinfo function
private void fetchUserInfo() {
accessToken = AccessToken.getCurrentAccessToken();
Toast.makeText(getApplicationContext(),
"Relogin successful?" + AccessToken.getCurrentAccessToken().getToken().toString(), Toast.LENGTH_LONG)
.show();
if (accessToken != null) {
GraphRequest request = GraphRequest.newMeRequest(accessToken, new GraphRequest.GraphJSONObjectCallback() {
#Override
public void onCompleted(JSONObject me, GraphResponse response) {
// LinkFacebook(socialService);
// FindFriends(socialService);
Token = accessToken.getToken().toString();
}
});
Bundle parameters = new Bundle();
parameters.putString(FIELDS, REQUEST_FIELDS);
request.setParameters(parameters);
GraphRequest.executeBatchAsync(request);
} else {
Toast.makeText(getApplicationContext(), "Relogin failed.", Toast.LENGTH_LONG).show();
}
}
However my accesstoken is still null.
Thanks
What I ended up doing was saving the token in sharedpreferences, then using it later in my app. That allowed me to use my tokens in all my activities.
Whether or not it will break later on down the line I'm not sure.
I just set up GCM in my Android App. But I have the problem that I don't know how to check if the device is already registered. I work with the new google play services library.
The register part looks like this:
#Override
protected String doInBackground(String... arg0) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context_app);
}
regid = gcm.register(SENDER_ID);
msg = "Dvice registered, registration ID=" + regid;
Log.d("111", msg);
sendRegistrationIdToBackend(regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
How can I modify this that it checks if the device is already registered?
Store the registration id in a databade table or shared preference and when app starting..check whether it is null or not
Google has provided very clear documentation with code.You should use following code:
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
GCMRegistrar.checkManifest(this);
registerReceiver(mHandleMessageReceiver,
new IntentFilter(DISPLAY_MESSAGE_ACTION));
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
// Automatically registers application on startup.
GCMRegistrar.register(this, SENDER_ID);
} else {
// Device is already registered on GCM, check server.
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
mDisplay.append(getString(R.string.already_registered) + "\n");
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
boolean registered =
ServerUtilities.register(context, regId);
// At this point all attempts to register with the app
// server failed, so we need to unregister the device
// from GCM - the app will try to register again when
// it is restarted. Note that GCM will send an
// unregistered callback upon completion, but
// GCMIntentService.onUnregistered() will ignore it.
if (!registered) {
GCMRegistrar.unregister(context);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}
#Override
protected void onDestroy() {
if (mRegisterTask != null) {
mRegisterTask.cancel(true);
}
unregisterReceiver(mHandleMessageReceiver);
GCMRegistrar.onDestroy(this);
super.onDestroy();
}
private final BroadcastReceiver mHandleMessageReceiver =
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
mDisplay.append(newMessage + "\n");
}
};
when you get registration Id, Store it in SharedPreferences, for example:
SharedPreferences shp = context.getSharedPreferences("anyNameYouLike",MODE_PRIVATE);
SharedPreferences.Editor editor=shp.edit();
editor.putString("RegID",registrationID).commit;
In the next time before you register check the "anyNameYouLike" if it contain field called RegID Like this:
private boolean isRegistered(Context context){
SharedPreferences shp = context.getSharedPreferences("anyNameYouLike",PRIVATE_MODE);
return shp.contains("RegID");
}
I have implemented an app where I user can can post in their facebook account.
But when I login as developer account then its working, but when I use different user id then it showing a message "Authentication with Facebook failed! "
btnPostStatus = (Button) findViewById(R.id.postStatus);
edtPost = (EditText)findViewById(R.id.post_text);
btnPostStatus.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
facebook = new Facebook(APP_ID);
restoreCredentials(facebook);
messagePost = edtPost.getText().toString();
if (!facebook.isSessionValid()) {
loginAndPostToWall();
} else {
postToWall(messagePost);
}
}
});
public void loginAndPostToWall() {
facebook.authorize(this, PERMISSIONS, Facebook.FORCE_DIALOG_AUTH,
new LoginDialogListener());
}
public void postToWall(String message) {
Bundle parameters = new Bundle();
parameters.putString("message", message);
parameters.putString("description", "topic share");
try {
facebook.request("me");
String response = facebook.request("me/feed", parameters, "POST");
Log.d("Tests", "got response: " + response);
if (response == null || response.equals("")
|| response.equals("false")) {
showToast("Blank response.");
} else {
showToast("Message posted to your facebook wall!");
}
} catch (Exception e) {
showToast("Failed to post to wall!");
e.printStackTrace();
}
}
In Facebook: Go to Mannage App-> Select your App-> Settings- Change Sandbox Mode to off.
It works.
Did you add this line to your manifest
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="#string/app_id"/>
and add app_id to your strings.xml file
Every time I run my app and it tries to connect to facebook it cancels. It is already authroized and I can connect on my normal Facebook app. I have been looking for a solution for about two days now and can't find any. This is really the only problem holding me back from finishing my app... Hopefully I can get some answers.
I am using this Facebook SDK
Here is my facebook authorize code:
public void authFB(){
Log.i("IN","FB - Authorizing");
fb.authorize(this, new String[]{ "publish_stream" }, new DialogListener(){
#Override
public void onComplete(Bundle values) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString("access_token", fb.getAccessToken());
editor.putLong("access_expires", fb.getAccessExpires());
editor.putString("post_id",values.getString("post_id"));
editor.commit();
Log.i("IN","Login Successful");
checkFB();
}
#Override
public void onFacebookError(FacebookError e) {
Log.i("IN","Login UnSuccessful - fb error");
e.printStackTrace();
checkFB();
}
#Override
public void onError(DialogError e) {
Log.i("IN","Login UnSuccessful - error");
e.printStackTrace();
checkFB();
}
#Override
public void onCancel() {
Log.i("IN","Login UnSuccessful - cancel");
checkFB();
}
});
}
Here is my onCreate:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
prefs = getPreferences(MODE_PRIVATE);
String access_token = prefs.getString("access_token", null);
//String post_id = prefs.getString("post_id",null);
long expires = prefs.getLong("access_expires",0);
if(access_token != null){
fb.setAccessToken(access_token);
}
if(expires != 0){
fb.setAccessExpires(expires);
}
if(!fb.isSessionValid()){
authFB();
}
I have ZERO ideas about what is wrong. I have tried it on two different phones now and this is the debug I get:
03-07 18:18:43.460: INFO/IN(6741): Login UnSuccessful - cancel
That means onCancel is being called.
CONFUSED.
Thanks.
Fixed it myself.
I kept getting this error because I had this in my manifest for my activities:
android:launchMode="singleInstance"
I am posting this because hopefully it will help someone in the future.
The reason why it created an error is because it tried to create a secondInstance (duh) and that isnt allowed.