Android: How to resolve Google API connection fail from a Service? - android

here is the code provided by the official guide, while this is a snippet causing problems.
#Override
public void onConnectionFailed(ConnectionResult result) {
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
mResolvingError = true;
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, REQUEST_RESOLVE_ERROR)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
mResolvingError = false;
}
});
}
}
If I use it in a Service, when you read the variable this passed as argument to those functions, they expect an Activity type.
How should I do? It's a Service.
For the same reason I can't get activity result
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
mResolvingError = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mGoogleApiClient.isConnecting() &&
!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
}
}

This answer assumes your service is a "started" service. If it is a bound service or intent service, indicate that in a comment and I'll update the description and code included here.
The solution I suggest is to implement the activity shown below to handle the resolution UI. Replace the onConnectionFailed() method in your service with this code to hand off the resolution processing to the ResolverActivity:
#Override
public void onConnectionFailed(ConnectionResult result) {
Intent i = new Intent(this, ResolverActivity.class);
i.putExtra(ResolverActivity.CONNECT_RESULT_KEY, result);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
Add the activity shown below to your app. When the connection request in your service fails, the connection result, which is a Parcelable, is passed to the activity. The activity handles the resolution UI and when finished, returns the status to the service as an intent extra. You will need to modify the code in your service's onStartCommand() to examine the extras in the intent to determine if it is being called to start the service for the first time, or to receive resolution status from the ResolverActivity.
An enhancement to this approach would be to post a notification with a PendingIntent for ResolverActivity instead of launching the activity immediately. That would give the user the option of deferring resolution of the connection failure.
public class ResolverActivity extends AppCompatActivity {
public static final String TAG = "ResolverActivity";
public static final String CONNECT_RESULT_KEY = "connectResult";
public static final String CONN_STATUS_KEY = "connectionStatus";
public static final int CONN_SUCCESS = 1;
public static final int CONN_FAILED = 2;
public static final int CONN_CANCELLED = 3;
// Request code to use when launching the resolution activity
private static final int REQUEST_RESOLVE_ERROR = 1111;
private static final String ERROR_CODE_KEY = "errorCode";
private static final String DIALOG_FRAG_TAG = "errorDialog";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate()");
// No content needed.
//setContentView(R.layout.activity_main);
Intent i = getIntent();
ConnectionResult result = i.getParcelableExtra(CONNECT_RESULT_KEY);
if (result.hasResolution()) {
try {
Log.i(TAG, "Starting error resolution...");
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent.
sendStatusToService(CONN_FAILED);
finish();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
ErrorDialogFragment.newInstance(result.getErrorCode())
.show(getSupportFragmentManager(), DIALOG_FRAG_TAG);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent result) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
if (resultCode == RESULT_OK) {
Log.i(TAG, "onActivityResult(): Connection problem resolved");
sendStatusToService(CONN_SUCCESS);
} else {
sendStatusToService(CONN_CANCELLED);
Log.w(TAG, "onActivityResult(): Resolution cancelled");
}
// Nothing more to do in this activity
finish();
}
}
private void sendStatusToService(int status) {
Intent i = new Intent(this, MyGoogleApiService.class);
i.putExtra(CONN_STATUS_KEY, status);
startService(i);
}
// Fragment to display an error dialog
public static class ErrorDialogFragment extends DialogFragment {
public static ErrorDialogFragment newInstance(int errorCode) {
ErrorDialogFragment f = new ErrorDialogFragment();
// Pass the error that should be displayed
Bundle args = new Bundle();
args.putInt(ERROR_CODE_KEY, errorCode);
f.setArguments(args);
return f;
}
#Override
#NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the error code and retrieve the appropriate dialog
int errorCode = getArguments().getInt(ERROR_CODE_KEY);
return GooglePlayServicesUtil.getErrorDialog(
errorCode, getActivity(), REQUEST_RESOLVE_ERROR);
}
#Override
public void onDismiss(DialogInterface dialog) {
Log.i(TAG, "Dialog dismissed");
}
}
}

Related

Activity cannot be cast to another activity

From a Fragment I am calling another fragment that reads barcodes using the camera.
This is how am I calling the scan fragment:
public void scanNow(View view){
// add fragment
ScanFragment firstFragment = new ScanFragment();
((MainActivityDriver)getActivity()).getSupportFragmentManager().beginTransaction()
.add(R.id.frame, firstFragment).commit();
}
public void scanResultData(String codeFormat, String codeContent){
// display it on screen
txtCode.setText("CONTENT: " + codeContent);
}
public void scanResultData(NoScanResultException noScanData) {
Toast toast = Toast.makeText(getActivity(),noScanData.getMessage(), Toast.LENGTH_SHORT);
toast.show();
}
The camera is working fine and scans the barcode, but then I am getting an exception at onactivityresult method at fragment scanfragment:
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
//retrieve scan result
IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
ScanResultReceiver parentActivity = (ScanResultReceiver) this.getActivity();
if (scanningResult != null) {
//we have a result
codeContent = scanningResult.getContents();
codeFormat = scanningResult.getFormatName();
// send received data
parentActivity.scanResultData(codeFormat,codeContent);
}else{
// send exception
parentActivity.scanResultData(new NoScanResultException(noResultErrorMsg));
}
}
at line:
ScanResultReceiver parentActivity = (ScanResultReceiver) this.getActivity();
This is the error:
Caused by: java.lang.ClassCastException: com.juarezserver.sdocksdriver.activity.MainActivityDriver cannot be cast to com.juarezserver.sdocksdriver.fragment.ScanResultReceiver
ScanResultReceiver is as follows:
public interface ScanResultReceiver {
/**
* function to receive scanresult
* #param codeFormat format of the barcode scanned
* #param codeContent data of the barcode scanned
*/
public void scanResultData(String codeFormat, String codeContent);
public void scanResultData(NoScanResultException noScanData);
}
How could I get it working?
You need to implement the interface ScanResultReceiver in MainActivityDriver
public static class MainActivityDriver extends Activity
implements ScanResultReceiver{
...
public void scanResultData(String codeFormat, String codeContent) {
//handle result
}
public void scanResultData(NoScanResultException noScanData) {
//handle exception
}
}
Also, I will recommend using a global callback variable in your fragment to avoid NullPointerException,
public class ScanFragment{
ScanResultReceiver resultCallback;
public interface ScanResultReceiver {
public void scanResultData(String codeFormat, String codeContent);
public void scanResultData(NoScanResultException noScanData);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
resultCallback = (ScanResultReceiver) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement ScanResultReceiver");
}
}
...
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
//retrieve scan result
IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanningResult != null) {
//we have a result
codeContent = scanningResult.getContents();
codeFormat = scanningResult.getFormatName();
// send received data
resultCallback.scanResultData(codeFormat,codeContent);
}else{
// send exception
resultCallback.scanResultData(new NoScanResultException(noResultErrorMsg));
}
}
}

Call DialogFragment from a custom Fragment, then set its property

After having successfully followed the guide Accessing Google APIs, I am trying to move all the Google+ related code from my MainActivity to a separate custom GoogleFragment.
However I am stuck at the very last spot - in my custom Fragment, I don't know how to access the mResolvingError field after the DialogFragment has been dismissed:
public class GoogleFragment extends Fragment
implements GoogleApiClient.OnConnectionFailedListener {
private boolean mResolvingError = false; // HOW TO ACCESS?
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (connectionResult.hasResolution()) {
try {
mResolvingError = true;
connectionResult.startResolutionForResult(getActivity(), REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent. Try again.
if (mGoogleApiClient != null)
mGoogleApiClient.connect();
}
} else {
// Show dialog using GoogleApiAvailability.getErrorDialog()
showErrorDialog(connectionResult.getErrorCode());
mResolvingError = true;
}
}
private void showErrorDialog(int errorCode) {
// Create a fragment for the error dialog
ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
// Pass the error that should be displayed
Bundle args = new Bundle();
args.putInt(ARGS_DIALOG_ERROR, errorCode);
dialogFragment.setArguments(args);
dialogFragment.show(getActivity().getSupportFragmentManager(), TAG_DIALOG_ERROR);
}
public static class ErrorDialogFragment extends DialogFragment {
public ErrorDialogFragment() {
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the error code and retrieve the appropriate dialog
int errorCode = this.getArguments().getInt(ARGS_DIALOG_ERROR);
return GoogleApiAvailability.getInstance().getErrorDialog(
this.getActivity(),
errorCode,
REQUEST_RESOLVE_ERROR);
}
#Override
public void onDismiss(DialogInterface dialog) {
mResolvingError = false; // DOES NOT COMPILE
}
}
}
What should I do here please?
If I make the ErrorDialogFragment non-static I get compile error:
This fragment inner class should be static
(GoogleFragment.ErrorDialogFragment)
If I keep it static - I can not access the variable either.
I am thinking of 2 workarounds for my problem:
Using LocalBroadcastManager to send a custom Intent from ErrorDialogFragment to GoogleFragment
Define a custom method in GoogleFragment and access it through getSupportFragmentManager().findFragmentByTag()
But is there maybe a simpler solution?
UPDATE:
I've changed the mResolvingError field to public and have tried this code:
#Override
public void onDismiss(DialogInterface dialog) {
GoogleFragment f = (GoogleFragment) getActivity().getSupportFragmentManager().findFragmentByTag(GoogleFragment.TAG);
if (f != null && f.isVisible()) {
f.mResolvingError = false;
}
}
but I am not sure how to test this properly and if f.isVisible() is needed there...
UPDATE 2:
Maybe I should somehow use DialogInterface.OnDismissListener with GoogleApiAvailability.getInstance().getErrorDialog in my code?
BladeCoder's comments have been very insightful, thanks.
However I have realized, that all the hassle with saving and restoring mResolvingError is unnecessary, because startResolutionForResult() starts a separate Activity anyway and obstructs my app - so it doesn't really matter if I rotate device or not.
Here is my final code to initiate GCM and fetch Google+ user data -
MainActivity.java:
public static final int REQUEST_GOOGLE_PLAY_SERVICES = 1972;
public static final int REQUEST_GOOGLE_PLUS_LOGIN = 2015;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null)
startRegistrationService();
}
private void startRegistrationService() {
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
int code = api.isGooglePlayServicesAvailable(this);
if (code == ConnectionResult.SUCCESS) {
onActivityResult(REQUEST_GOOGLE_PLAY_SERVICES, Activity.RESULT_OK, null);
} else if (api.isUserResolvableError(code) &&
api.showErrorDialogFragment(this, code, REQUEST_GOOGLE_PLAY_SERVICES)) {
// wait for onActivityResult call (see below)
} else {
String str = GoogleApiAvailability.getInstance().getErrorString(code);
Toast.makeText(this, str, Toast.LENGTH_LONG).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
if (resultCode == Activity.RESULT_OK) {
Intent i = new Intent(this, RegistrationService.class);
startService(i); // OK, init GCM
}
break;
case REQUEST_GOOGLE_PLUS_LOGIN:
if (resultCode == Activity.RESULT_OK) {
GoogleFragment f = (GoogleFragment) getSupportFragmentManager().
findFragmentByTag(GoogleFragment.TAG);
if (f != null && f.isVisible())
f.onActivityResult(requestCode, resultCode, data);
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
GoogleFragment.java:
public class GoogleFragment extends Fragment
implements View.OnClickListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
public final static String TAG = "GoogleFragment";
private GoogleApiClient mGoogleApiClient;
private ImageButton mLoginButton;
private ImageButton mLogoutButton;
public GoogleFragment() {
// required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_google, container, false);
mGoogleApiClient = new GoogleApiClient.Builder(getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.build();
mLoginButton = (ImageButton) v.findViewById(R.id.login_button);
mLoginButton.setOnClickListener(this);
mLogoutButton = (ImageButton) v.findViewById(R.id.logout_button);
mLogoutButton.setOnClickListener(this);
return v;
}
private void googleLogin() {
mGoogleApiClient.connect();
}
private void googleLogout() {
if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected())
mGoogleApiClient.disconnect();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK)
mGoogleApiClient.connect();
}
#Override
public void onClick(View v) {
if (v == mLoginButton)
googleLogin();
else
googleLogout();
}
#Override
public void onConnected(Bundle bundle) {
Person me = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
if (me != null) {
String id = me.getId();
Person.Name name = me.getName();
String given = name.getGivenName();
String family = name.getFamilyName();
boolean female = (me.hasGender() && me.getGender() == 1);
String photo = null;
if (me.hasImage() && me.getImage().hasUrl()) {
photo = me.getImage().getUrl();
photo = photo.replaceFirst("\\bsz=\\d+\\b", "sz=300");
}
String city = "Unknown city";
List<Person.PlacesLived> places = me.getPlacesLived();
if (places != null) {
for (Person.PlacesLived place : places) {
city = place.getValue();
if (place.isPrimary())
break;
}
}
Toast.makeText(getContext(), "Given: " + given + ", Family: " + family + ", Female: " + female + ", City: " + city, Toast.LENGTH_LONG).show();
}
}
#Override
public void onConnectionSuspended(int i) {
// ignore? don't know what to do here...
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(getActivity(), MainActivity.REQUEST_GOOGLE_PLUS_LOGIN);
} catch (IntentSender.SendIntentException e) {
mGoogleApiClient.connect();
}
} else {
int code = connectionResult.getErrorCode();
String str = GoogleApiAvailability.getInstance().getErrorString(code);
Toast.MakeText(getContext(), str, Toast.LENGTH_LONG).show();
}
}
}

I just tried to use the onActivitiResult of other activities

Google Login connect Error
Android Code..
public class GooglePlusPlugin implements ConnectionCallbacks,
OnConnectionFailedListener{
Activity resultactivity;
private Activity activity;// activity is Unity3D currentActivity
public void init(String objName, String CallbackName) {
callbackName = CallbackName;
unityObjectName = objName;
mApiClient = new GoogleApiClient.Builder(activity, this, this)
.addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE).build();
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
resultactivity = new ResultActivity();
mConnectionProgressDialog = new ProgressDialog(activity);
mConnectionProgressDialog.setMessage("Signing in...");
}
});
}
#Override
public void onConnectionFailed(final ConnectionResult result) {
if (!mConnectionProgressDialog.isShowing()) {
if (result.hasResolution()) {
try {
result.startResolutionForResult(resultactivity,
result.getErrorCode());
return;
} catch (SendIntentException e) {
mApiClient.connect();
}
}
}
}
}
startResolutionForResult a call to onActivityResult
I try to use onActivityResult other activities, because not extends the activity in GooglePlusPlugin
public class ResultActivity extends FragmentActivity
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_RESOLVE_ERR
&& resultCode == RESULT_OK) {
GooglePlusPlugin.getInstance().reconnect(requestCode, resultCode);
finish();
}
}
but failed...
error is
Caused by: java.lang.NullPointerException
at android.app.Activity.startIntentSenderForResultInner(Activity.java:3560)
at android.app.Activity.startIntentSenderForResult(Activity.java:3536)
at android.app.Activity.startIntentSenderForResult(Activity.java:3503)
at com.google.android.gms.common.ConnectionResult.startResolutionForResult(Unknown Source)
at kr.co.crooz.plugin.googleplus.GooglePlusPlugin.onConnectionFailed(GooglePlusPlugin.java:212)
Why startIntentSenderForResult need, I do not know how to use it.
How to solve?
Thanks for reading long code
private Activity activity; Activity has already been taken from another part.
I like long content. The part that is not.
try {
this.unityPlayerClass = Class
.forName("com.unity3d.player.UnityPlayer");
this.unityPlayerActivityField = this.unityPlayerClass
.getField("currentActivity");
this.unitySendMessageMethod = this.unityPlayerClass.getMethod(
"UnitySendMessage", new Class[] { String.class,
String.class, String.class });
this.activity = getActivity();
}
private Activity getActivity() {
if (this.unityPlayerActivityField != null) {
try {
Activity activity = (Activity) this.unityPlayerActivityField
.get(this.unityPlayerClass);
if (activity == null) {
Log.d(TAG,
"Something has gone terribly wrong. The Unity Activity does not exist. This could be due to a low memory situation");
}
return activity;
} catch (Exception e) {
Log.d(TAG, "error getting currentActivity: " + e.getMessage());
}
}
return this.activity;
}
your Activity is null
private Activity activity;// activity is Unity3D currentActivity
you declare it here but you never grab the activity from unity3D as i guess you trying to do, this will result that you activity is null and will throw nullpointerexeption

Android Google+ issues

I want to do the post on google-plus through my app. I am using this code for that but it not working it giving me message that I couldn't post the message and I also having a doubt where i will use my clientId?.please help me.
public class MainActivity extends Activity implements OnClickListener,
ConnectionCallbacks, OnConnectionFailedListener {
private static final String TAG = "ExampleActivity";
private static final int REQUEST_CODE_RESOLVE_ERR = 9000;
private ProgressDialog mConnectionProgressDialog;
private PlusClient mPlusClient;
private ConnectionResult mConnectionResult;
private Button shareButton=null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
shareButton=(Button)findViewById(R.id.share_button);
shareButton.setOnClickListener(this);
mPlusClient = new PlusClient.Builder(this, this, this)
.setActions("http://schemas.google.com/AddActivity", "http://schemas.google.com/BuyActivity")
.setScopes(Scopes.PLUS_LOGIN) // recommended login scope for social features
// .setScopes("profile") // alternative basic login scope
.build();
// Progress bar to be displayed if the connection failure is not resolved.
mConnectionProgressDialog = new ProgressDialog(this);
mConnectionProgressDialog.setMessage("Signing in...");
}
#Override
protected void onStart() {
super.onStart();
mPlusClient.connect();
}
#Override
protected void onStop() {
super.onStop();
mPlusClient.disconnect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
if (mConnectionProgressDialog.isShowing()) {
// The user clicked the sign-in button already. Start to resolve
// connection errors. Wait until onConnected() to dismiss the
// connection dialog.
if (result.hasResolution()) {
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLVE_ERR);
} catch (SendIntentException e) {
mPlusClient.connect();
}
}
}
// Save the result and resolve the connection failure upon a user click.
mConnectionResult = result;
}
#Override
protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
if (requestCode == REQUEST_CODE_RESOLVE_ERR && responseCode == RESULT_OK) {
mConnectionResult = null;
mPlusClient.connect();
}
}
#Override
public void onConnected(Bundle connectionHint) {
String accountName = mPlusClient.getAccountName();
Toast.makeText(this, accountName + " is connected.", Toast.LENGTH_LONG).show();
}
#Override
public void onDisconnected() {
Log.d(TAG, "disconnected");
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.share_button:
Intent shareIntent = new PlusShare.Builder(this)
.setType("text/plain")
.setText("Welcome to the Google+ platform.")
.setContentUrl(Uri.parse("https://developers.google.com/+/"))
.getIntent();
startActivityForResult(shareIntent, 0);
break;
}
}
}
Thanks in advance
You don't need a client ID anywhere in the app - its inferred from the app packagename and the SHA1 of the signing key (which is why it asks for those in the API console). However, you don't need sign in or a key at all to do the kind of basic sharing you're doing. To test, you might want to remove all PlusClient/sign in related code until you're comfortable the PlusShare builder is creating the intent properly.
Could you make sure you're using the latest version of Google Play services (4.1) and see if you have any issues still? If so, could you check whether any more error details appear in logcat.

Using share dialog in Android Facebook SDK. How to know is user actually shared or cancelled sharing activity?

I have added sharing functionality to Android app as described here https://developers.facebook.com/docs/android/share-dialog/#setup
But I have noticed that if user is cancelled sharing activity onComplete is called anyway
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data, new FacebookDialog.Callback() {
#Override
public void onError(FacebookDialog.PendingCall pendingCall, Exception error, Bundle data) {
Log.e("Activity", String.format("Error: %s", error.toString()));
}
#Override
public void onComplete(FacebookDialog.PendingCall pendingCall, Bundle data) {
Log.e("Activity", "Success!");
}
});
}
I have also looked in to Bundle which is returned. Even if I cancel share dialog I get
com.facebook.platform.extra.DID_COMPLETE=true
How can I get result that user really shared data on facebook? (Without making separate login with facebook button. Maybe some permissions need to be added?)
See https://developers.facebook.com/docs/android/share-dialog/#handling-responses
You can tell if the user has cancelled by calling
String gesture = FacebookDialog.getNativeDialogCompletionGesture(data);
if (gesture != null) {
if ("post".equals(gesture)) {
// the user hit Post
} else if ("cancel".equals(gesture)) {
// the user hit cancel
} else {
// unknown value
}
} else {
// either an error occurred, or your app has never been authorized
}
where data is the result bundle. However, it will only return a non-null value IF the user has logged in via your app (i.e. you have at least basic_info permissions). If the user has never logged in or authorized your app, then the only thing you'll see is the DID_COMPLETE, and it will always be true unless an error occurred. This is by design.
In order to obtain the result for the sharing, your app needs to have at least the basic_info permission.
To solve that, just open an session (this will automatically request the basic_info permission):
Session.openActiveSession(this /*your activity*/,
true /*allows the UI login to show up if needed*/,
new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
Log.i("[Facebook]", "Session: " + state.toString());
if (session.isOpened()) {
/// now you are good to get the sharing results
}
}
});
You can find more information in here: https://developers.facebook.com/docs/android/getting-started/
Implement FacebookCallback<Sharer.Result> to know whether sharing was successful or cancelled or there was an error.
You can use the code below in Activity and in Fragment as well. When using in Fragment make sure you pass this in ShareDialog constructor. If you pass getActivity() then onActivityResult method will not be triggered in Fragment.
private CallbackManager callbackManager;
private void shareYourContentOnFacebook() {
callbackManager = CallbackManager.Factory.create();
ShareDialog shareDialog = new ShareDialog(this);
shareDialog.registerCallback(callbackManager, new FacebookCallback<Sharer.Result>() {
#Override
public void onSuccess(Sharer.Result result) {
Log.d(this.getClass().getSimpleName(), "shared successfully");
//add your code to handle successful sharing
}
#Override
public void onCancel() {
Log.d(this.getClass().getSimpleName(), "sharing cancelled");
//add your code to handle cancelled sharing
}
#Override
public void onError(FacebookException error) {
Log.d(this.getClass().getSimpleName(), "sharing error");
//add your code to handle sharing error
}
});
if (ShareDialog.canShow(ShareLinkContent.class)) {
ShareLinkContent shareLinkContent = new ShareLinkContent.Builder()
.setContentTitle("Your content title")
.setContentDescription("Your content description")
.setContentUrl(Uri.parse(""http://your-content-url.com""))
.build();
shareDialog.show(shareLinkContent);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
callbackManager.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onComplete(FacebookDialog.PendingCall pendingCall, Bundle data) {
if (data.getString("com.facebook.platform.extra.COMPLETION_GESTURE").equals("cancel"))
return;
}
the value of data.getString("com.facebook.platform.extra.COMPLETION_GESTURE") is "post" when the user did post on Facebook.
Use this code:-
/**
* Facebook Dialog Callback
*
* Called up when come back from Share Dialog
*
*/
private class FacebookDialogCallBack implements FacebookDialog.Callback
{
#Override
public void onComplete(PendingCall pendingCall, Bundle data)
{
//Show Toast Message
showToastMessage(data);
}
#Override
public void onError(PendingCall pendingCall, Exception error, Bundle data)
{
//Show Toast Message
showToastMessage(data);
}
}
//Show Toast Message
private void showToastMessage(Bundle data)
{
//Get Native Dialog Did Complete
boolean didComplete = FacebookDialog.getNativeDialogDidComplete(data);
if(didComplete)
{
//Get Native Dialog Completion Gesture
String nativeDialogCompletionGesture = FacebookDialog.getNativeDialogCompletionGesture(data);
if (nativeDialogCompletionGesture == null || FacebookDialog.COMPLETION_GESTURE_CANCEL.equals(nativeDialogCompletionGesture))
{
//Show Publish Cancel Toast
UIUtil.showToast(R.string.toast_message_share_publish_cancelled);
}
else
{
//Show Success Post Toast
UIUtil.showToast(R.string.toast_message_share_success_post);
}
}
else
{
//Show Publish Cancel Toast
UIUtil.showToast(R.string.toast_message_share_publish_cancelled);
}
}
Heading ## private static ShareDialog shareDialog;
private static FacebookCallback<Sharer.Result> shareCallback = new FacebookCallback<Sharer.Result>() {
#Override
public void onCancel() {
Log.d("HelloFacebook", "Canceled");
}
#Override
public void onError(FacebookException error) {
Log.d("HelloFacebook", String.format("Error: %s", error.toString()));
String title = this.getActivty().getString(R.string.error);
String alertMessage = error.getMessage();
showResult(title, alertMessage);
}
#Override
public void onSuccess(Sharer.Result result) {
Log.d("HelloFacebook", "Success!");
// 不为空,才分享成功
if (result.getPostId() != null) {
String title = this.getActivty().getString(R.string.success);
String id = result.getPostId();
String alertMessage = this.getActivty().getString(R.string.successfully_posted_post, id);
showResult(title, alertMessage);
}
}
private void showResult(String title, String alertMessage) {
new AlertDialog.Builder(this.getActivty())
.setTitle(title)
.setMessage(alertMessage)
.setPositiveButton(R.string.ok, null)
.show();
}
};
protected void onCreate (Bundle savedInstanceState)
{
shareDialog = new ShareDialog(this. getActivty());
shareDialog.registerCallback( callbackManager, shareCallback);
}

Categories

Resources