I'm trying to get publish permissions from my users in my Android app and I'm succeeding but when I get the permission I want a callback to tell me just that. Here is my code:
private void requestPublishPermissions(Session session) {
Log.d("", "Requesting Publish Permissions...");
if (session != null) {
List<String> publishPermissions = Arrays.asList("publish_actions", "publish_stream");
final int REAUTH_ACTIVITY_CODE = 100;
Session.NewPermissionsRequest reauthRequest = new Session.NewPermissionsRequest(this, publishPermissions).setRequestCode(REAUTH_ACTIVITY_CODE);
reauthRequest.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
session.requestNewPublishPermissions(reauthRequest);
}
}
Does the session.requestNewPublishPermissions(reauthRequest); have a callback or something that tells me that the permission was accepted?
Thanks for any input
I don't know of a callback for that request, but there's an easy way to get your desired result.
Just add a conditional to the onSessionStateChanged() callback. If you check for the permission in that method by using session.getPermissions().contains("xxx"), you should be able to check in there. Any time the session state changes, it'll call that method, and I think that includes updating permissions.
You can manually add callbacks to your FB session.
Session.getActiveSession().addCallback(new StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
if (session.getPermissions().contains("publish_actions")) {
//do stuff
}
}
});
Add the StatusCallback to your session.
private Session.StatusCallback statusCallback = new SessionStatusCallback();
private class SessionStatusCallback implements Session.StatusCallback {
#Override
public void call(final Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
switch (state) {
case OPENED_TOKEN_UPDATED:
// Returns here after you request publish permissions
// So call your publishing actions here
break;
}
}
}
}
Implement onActivityResult() which glues things together.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
Related
I'm trying to use the DriveApi in order to create some folders and upload a text file with some data for a user.
I've tried implementing the quick-start guide from (link), but it has a few fundamental issues:
The api gets connected at onResume so the user will get prompted to give access to the app immediately after he opens the app which is confusing and scary.
If you deny or press the back button at the consent screen, the onResume method will get called again and the consent screen will be shown one more time, leading to an infinite loop.
I would rather like to connect the api when the user actually needs to store data so that will make more sense to the user. I tried doing it like this:
ResultCallback<DriveFolder.DriveFolderResult> folderCreatedCallback = new
ResultCallback<DriveFolder.DriveFolderResult>() {
#Override
public void onResult(#NonNull DriveFolder.DriveFolderResult result) {
clearCurrentAction();
if (!result.getStatus().isSuccess()) {
Log.e(TAG, "Error while trying to create the folder");
return;
}
Log.d(TAG, "Created a folder: " + result.getDriveFolder().getDriveId());
}
};
public DriveApiHelper(GoogleApiClient mGoogleApiClient) {
this.mGoogleApiClient = mGoogleApiClient;
}
public void createBackupsFolder() {
currentAction = DriveActions.CREATING_FOLDER;
if (mGoogleApiClient.isConnected()) {
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("test").build();
Drive.DriveApi.getRootFolder(mGoogleApiClient).createFolder(
mGoogleApiClient, changeSet).setResultCallback(folderCreatedCallback);
} else {
mGoogleApiClient.connect();
}
}
and this is how my onResume and onConnected methods look like:
#Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
// Create the API client and bind it to an instance variable.
// We use this instance as the callback for connection and connection
// failures.
// Since no account name is passed, the user is prompted to choose.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mDriveHelper = new DriveApiHelper(mGoogleApiClient);
}
//Log.d(TAG, mDriveHelper.getCurrentAction() + "");
Log.d("test", "Connected " + mGoogleApiClient.isConnected());
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
switch (mDriveHelper.getCurrentAction()) { //resume the last action
case CREATING_FOLDER:
mDriveHelper.createBackupsFolder();
break;
}
}
I was hoping that keeping a reference of what the user tried to do when the api was asked to connect, I can resume that action after the api successfully connected. This is the closest implementation I've got to fit my needs, but after actually clicking the 'Allow' button from the consent screen none of the api callbacks gets called (onConnected, onConnectionFailed).
I actually need to call the connect method one more time in order to get connected and also fire the onConnected successfully resuming the users' action.
Turns out that I forgot about overriding onActivityResult (it wasn't mentioned in the documentation at that time and I don't know if they included it now)
Just add:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_CODE_RESOLUTION) {
mGoogleApiClient.connect();
}
} else {
if (requestCode == REQUEST_CODE_RESOLUTION) {
mDriveHelper.dismissStatusDialog();
}
}
}
Using Facebook android sdk version 4.1.1, I managed to open a shareDialog and share a content using the below code:
if (ShareDialog.canShow(ShareLinkContent.class)) {
ShareLinkContent linkContent = new ShareLinkContent.Builder()
.setContentTitle("Hello Facebook")
.setContentDescription(
"The 'Hello Facebook' sample showcases simple Facebook integration")
.setContentUrl(Uri.parse("http://developers.facebook.com/android"))
.build();
shareDialog.show(linkContent);
shareDialog.registerCallback(callbackManager, new FacebookCallback<Sharer.Result>() {
#Override
public void onSuccess(Result result) {
//always gets called
}
#Override
public void onCancel() {
//do something
}
#Override
public void onError(FacebookException error) {
// TODO Auto-generated method stub
}
});
}
and the callback on ActivityResult code:
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
callbackManager.onActivityResult(requestCode, resultCode, data);
}
the resultCode is always -1 which is RESULT_OK regardless whether user pressed back or post button of the dialog. and the callback's onSuccess function is always called and the postId is always null regardless whether the content is posted or cancelled. Anyone know why is it acting this way?
According to THIS which is a reported bug on facebook developers bug section, this is known and according to the answers given, it seems it's in the design that any form of closing the dialog is considered as success.
I'm using SDK 7.1.0 and this no longer appears to be an issue. Both the native and web share dialogs are calling the correct callback methods.
I am working on restoring SMS on KITKAT. Referring to this article I have added the things which are required to set my app as default app for SMS. After adding all required things in manifest file I have write the following code:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
mDefaultSmsApp = Telephony.Sms.getDefaultSmsPackage(mContext);
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, mContext.getPackageName());
mContext.startActivity(intent);
}
The above code shows this dialog but I am unable to get the result from this activity/dialog either user clicked on Yes or No because I want to add listener or get any code which should represent that the user clicked on these buttons.
Thanks.
One way to do this is to fire the Intent with startActivityForResult(), and then check the resultCode in the onActivityResult() method. Please note that I've changed the code in the example to run in an Activity's Context.
private static final int DEF_SMS_REQ = 0;
private String mDefaultSmsApp;
...
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
mDefaultSmsApp = Telephony.Sms.getDefaultSmsPackage(this);
if (!getPackageName().equals(mDefaultSmsApp))
{
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getPackageName());
startActivityForResult(intent, DEF_SMS_REQ);
}
}
...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case DEF_SMS_REQ:
boolean isDefault = resultCode == Activity.RESULT_OK;
...
}
}
As mentioned in a comment below, apparently checking the result code is not 100% reliable. A safer check is to simply compare your app's package name to the current default in onActivityResult(). There's no need to check the result code at all, like the answer linked in the comment shows.
String currentDefault = Sms.getDefaultSmsPackage(this);
boolean isDefault = getPackageName().equals(currentDefault);
The way you can react on "yes" button click:
private String mDefSmsPackage;
#Override
public void onCreate(#Nullable Bundle state) {
//...
mDefSmsPackage = Telephony.Sms.getDefaultSmsPackage(getActivity())
}
#Override
public void onResume() {
super.onResume();
String newDefSmsPkg = Telephony.Sms.getDefaultSmsPackage(getActivity());
if (!TextUtils.equals(mDefSmsPackage, newDefSmsPkg)) {
mDefSmsPackage = newDefSmsPkg;
//ON DEF SMS APP CAHNGE...
}
}
since hours I am trying to figure out why my facebook-connect is not working properly. I always have to click it two times.. the first time I click it I see that the facbeook dialog is opening but its not calling any kind of callback so my Login-Activity is just "resuming".
public void onClick_fbIcon(View v) {
if(!buttonsEnabled)
return;
buttonsEnabled = false;
tryFacebookConnect();
}
#SuppressWarnings("deprecation")
private void tryFacebookConnect() {
Log.d("debug", "start fbc");
doingFacebooklogin = true;
facebook.authorize(this, new DialogListener() {
public void onComplete(Bundle values) {
end();
toast("Complete");
Log.d("debug", "#0");
// .. continue with main code
}
public void onFacebookError(FacebookError error) {
end();
Log.d("debug", "#1");
}
public void onError(DialogError e) {
end();
Log.d("debug", "#2");
}
public void onCancel() {
end();
Log.d("debug", "#3");
}
private void end() {
Log.d("debug", "fbc complete");
doingFacebooklogin = false;
}
});
}
The first click I only get "start fbc" but nothing after that, so I guess that no callback method is called.
I found out that when the facebook-connect is not working the first time, "onResume is called". The next time onActivityResult is called.
#SuppressWarnings("deprecation")
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("debug", "Main: onActivityResult");
super.onActivityResult(requestCode, resultCode, data);
facebook.authorizeCallback(requestCode, resultCode, data);
}
My login activity is an intent started by my main activity that is specifing if a login is needed at all:
Intent intent = new Intent(this, Login.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
Sometimes I can see the following error:
11-22 10:23:39.684: D/Facebook-publish(7317): Can NOT get FbInjector instance! Probably because this method was called in ContentProvider's onCreate.
Please take a look at this Tutorial. I just Follow this and I make it all works perfectly.
Hope that it will help you too.
http://www.youtube.com/watch?v=xndi6s9Tn_U
I don't know why but the problem is obviously part of the facebook-sdk. I found out that this problem does not occur if I have no facebook-app installed on my device. So I changed my code like this:
facebook.authorize(a, new String[] { }, **Facebook.FORCE_DIALOG_AUTH**, new DialogListener() {
...
I have the below script running and it works perfectly. What I am wondering is. Why does facebook give me a secret key if I dont have to implement it as I have not below.
Facebook facebook = new Facebook("APP_ID"); // Application ID of your app at facebook
boolean isLoggedIn = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Implementing SSO
facebook.authorize(this, new String[]{"publish_stream"}, new DialogListener(){
#Override
public void onComplete(Bundle values) {
//control comes here if the login was successful
// Facebook.TOKEN is the key by which the value of access token is stored in the Bundle called 'values'
Log.d("COMPLETE","AUTH COMPLETE. VALUES: "+values.size());
Log.d("AUTH TOKEN","== "+values.getString(Facebook.TOKEN));
updateStatus(values.getString(Facebook.TOKEN));
}
#Override
public void onFacebookError(FacebookError e) {
Log.d("FACEBOOK ERROR","FB ERROR. MSG: "+e.getMessage()+", CAUSE: "+e.getCause());
}
#Override
public void onError(DialogError e) {
Log.e("ERROR","AUTH ERROR. MSG: "+e.getMessage()+", CAUSE: "+e.getCause());
}
#Override
public void onCancel() {
Log.d("CANCELLED","AUTH CANCELLED");
}
});
}
//updating Status
public void updateStatus(String accessToken){
try {
Bundle bundle = new Bundle();
bundle.putString("message", "test update"); //'message' tells facebook that you're updating your status
bundle.putString(Facebook.TOKEN,accessToken);
//tells facebook that you're performing this action on the authenticated users wall, thus
// it becomes an update. POST tells that the method being used is POST
String response = facebook.request("me/feed",bundle,"POST");
Log.d("UPDATE RESPONSE",""+response);
} catch (MalformedURLException e) {
Log.e("MALFORMED URL",""+e.getMessage());
} catch (IOException e) {
Log.e("IOEX",""+e.getMessage());
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("onActivityResult","onActivityResult");
facebook.authorizeCallback(requestCode, resultCode, data);
}
The most likely reason is that you had already logged on for this app, or had previously logged on with the Facebook app, as a result of which Facebook had allocated you an access token - which is then valid until the app explicitly signs off, or the user disables app access (in the Facebook server-side user profile).
So when you do the authorize, the underlying Facebook SDK simply retrieves the access token, and you do not need to login.
You can disable the access token by going to Facebook for your user and doing Account settings (drop down at top right), then Apps (at left) and disabling your app's access. At which point, when you next run your app, the user will have to log in to Facebook and authorize your app.