CommentThreads: insert gives 403 Forbidden - java

I'm going nuts with this error. As far as I can see I've followed the instructions correctly. My scopes are YOUTUBE_FORCE_SSL. In desperation I've tried to add all Google Plus Scopes without luck. Still get the same error, both in the device, emulator and Google Api Explorer. The video I try to comment on are public. I have a Google+ profile and are signed in with it when I try to make a comment.
This is the full error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "youtube.commentThread",
"location" : "Authorization",
"locationType" : "header",
"message" : "The callers YouTube account is not connected to Google+.",
"reason" : "ineligibleAccount"
} ],
"message" : "The callers YouTube account is not connected to Google+."
}
This is my code:
try {
HashMap<String, String> parameters = new HashMap<>();
parameters.put("part", "snippet");
CommentThread commentThread = new CommentThread();
CommentThreadSnippet snippet = new CommentThreadSnippet();
Comment topLevelComment = new Comment();
CommentSnippet commentSnippet = new CommentSnippet();
commentSnippet.set("textOriginal", textComment);
commentSnippet.set("channelId", channelId);
commentSnippet.set("videoId", ytId);
topLevelComment.setSnippet(commentSnippet);
snippet.setTopLevelComment(topLevelComment);
commentThread.setSnippet(snippet);
YouTube.CommentThreads.Insert commentThreadsInsertRequest = mService.commentThreads().insert(parameters.get("part"), commentThread);
CommentThread response = commentThreadsInsertRequest.execute();
Log.i("COMMENT:", response.toString());
}
Adding screenshot from Api Explorer:
Can you get CommentThreads: insert to work with the API Explorer? If so, how?
I have seen the answers to a similar question here and they don't solve this problem.
Any help is appreciated.
Edit 1
After further testing. Everything works fine with an old account I have. I've tried to see which settings could be different, so far without luck.
This also works if I switch to a YouTube brand account.
The problem remains, it don't work for all Google Accounts, not even when they're also Google+ accounts. The error seems to imply that the request is not made from a Google+ Account. Would be great if Google could clarify the exact reason.
Also, is it possible to programmatically make an account eligible to make a comment, after asking the permission from the account owner? How?
Edit 2
According to this page the reason for the error is this:
The YouTube account used to authorize the API request must be merged
with the user's Google account to insert a comment or comment thread.
How can this be done within the app?
Edit 3
I guess the answer can be found here. You're not able to comment without a YouTube Channel.
The problem is that you're not able to comment unless you have a private YouTube Channel or are logged in with your Brand Account. Using the model to login that Google gave in the instructions don't allow login with Brand Accounts, they're not visible in the account picker.
The result is that you're able to login with an account that have YouTube Brand Accounts, but you will not be able to comment using that accountand since you're not able to pick a Brand Account there is no way to solve this unless you ask users to also create a private Channel. The error message should say something like this:
The callers YouTube account is not a YouTube Channel Account.

If you have created a new account and if you haven't commented on any of the youtube videos, then it throws the error: "The callers YouTube account is not connected to Google+."
Solution: Atleast manually comment in any of the youtube videos using the new account and then try the API. It works smoothly.

Since you can't post comments without a private YouTube Channel(see edits above) the solution would look something like this. If you can find a better one, please submit!
1) Catch the Error. Give Alert with instructions.
2) Launch a Webview with this URL: https://m.youtube.com/create_channel?chromeless=1&next=/channel_creation_done
3) Monitor the Webview and determine when the URL change to the following: https://m.youtube.com/channel_creation_done. The URL indicates that a channel has been created.
4) Close the Webview and resend the authorized API request.
The URLs above were found here but the error code to catch is not the same as on that page. You should catch a 403 with "reason" : "ineligibleAccount".
Update June 29th, 2018
I got back to this issue today and got it working in an acceptable way. See my implementation below:
1. Catch the error 403 after user posted comment without YouTube Channel
if(mLastError.getMessage().contains("403") && mLastError.getMessage().contains("ineligibleAccount")) {
// Show Alert with instruction
showAlertCreate("Please Create a YouTube Channel!", "You need a personal YouTube Channel linked to your Google Account before you can comment. Don't worry, it's easy to create one!\n\n1) Tap on CREATE below and wait for page to load.\n\n2) Login if needed.\n\n3) Tap CREATE CHANNEL and wait until comment is posted.");
}
Code for Alert:
public void showAlertCreate(String title, String description) {
AlertDialog.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder = new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert);
} else {
builder = new AlertDialog.Builder(this);
}
builder.setTitle(title)
.setMessage(description)
.setPositiveButton(R.string.yes_create, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Start Youtube WebView to create Channel
Intent intent = new Intent(mContext, WebViewActivity.class);
startActivityForResult(intent, 777);
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
2. When user tap CREATE in Alert, open this WebView
Notice this code to start Intent in alert above:
// Start Youtube WebView to create Channel
Intent intent = new Intent(mContext, WebViewActivity.class);
startActivityForResult(intent, 777);
XML for WebView:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WebViewActivity">
<WebView
android:id="#+id/create_channel"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
Code for WebView:
public class WebViewActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
WebView createChannel = findViewById(R.id.create_channel);
createChannel.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
if (url!=null && url.contains("https://m.youtube.com/channel_creation_done")) {
view.setVisibility(View.INVISIBLE);
//Log.i("URLWEB", url);
Intent intent = new Intent();
intent.putExtra("created", "yes");
setResult(RESULT_OK, intent);
finish();
}
}
});
createChannel.loadUrl("https://m.youtube.com/create_channel?chromeless=1&next=/channel_creation_done");
}
}
3. Catch when user completed Create Channel step in your activity
In onActivityResult() include something like this:
if (requestCode == 777) {
if(resultCode == RESULT_OK) {
// Receive intent from WebView, if new Channel, repost comment/reply
String created = data.getStringExtra("created");
if(created.equals("yes")) {
// Posting the comment again
getResultsFromApi();
}
}
}
Not the cleanest solution but it works.

Related

Trying to send a picture with text to Instagram stories but com.instagram.share.ADD_TO_STORY does nothing

I have read a lot of information on various sites, but not a single method works. There are also a lot of old solutions on the sites that don't work either. Here is my code:
Uri stickerAssetUri = Uri.parse("https://firebasestorage.googleapis.com/v0/b/schooly-47238.appspot.com/o/miners%2Ffimw.png?alt=media&token=9798e9ea-15a0-4ef2-869b-63ce4dc95b78");
String sourceApplication = "com.egormoroz.schooly";
Intent intent = new Intent("com.instagram.share.ADD_TO_STORY");
intent.putExtra("source_application", sourceApplication);
intent.setType("image/зтп");
intent.putExtra("interactive_asset_uri", stickerAssetUri);
intent.putExtra("top_background_color", "#33FF33");
intent.putExtra("bottom_background_color", "#FF00FF");
Activity activity = getActivity();
activity.grantUriPermission(
"com.instagram.android", stickerAssetUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (activity.getPackageManager().resolveActivity(intent, 0) != null) {
activity.startActivityForResult(intent, 0);
}
When this part of the code is triggered, nothing happens to the application. It remains on the same screen.
Based on official documentation from https://developers.facebook.com/docs/instagram/sharing-to-stories/.
You can change this
intent.setType("image/зтп");
to
intent.setType("image/*");
or
intent.setType(MEDIA_TYPE_JPEG);
I think sourceApplication should be your Facebook App ID, not your package name.

setting badge when Firebase Cloud Message is received in Ionic App

I'm having a hard time getting responses to my questions lately and I'm not why. If I am not asking right, can someone please let me know so I can adjust?
I am building an app with Ionic but having issues sending badge numbers for Android via FCM. I can't find anything in the Firebase Docs. How do I set the badge count when a message is received?
Here is my thought process but I don't know how to get it to work:
when the message is received, use the ionic native badge plugin to set it
send the badge count using FCM payload
NOTE: I am using NodeJS implementation for Firebase
What I've tried
I am using the cordova-plugin-fcm plugin and the Android ShortcutBadger to set the badge, but I am unable to set the badge when the message is received. I was only able to set it when the app is already open by calling the shortcutbadger function in the MyFirebaseMessagingService java class (of the cordova-plugin-fcm). Below is the code I am using in my FCMPluginActivity java class:
// more imports here
import me.leolin.shortcutbadger.ShortcutBadger;
public class FCMPluginActivity extends Activity {
private static String TAG = "FCMPlugin";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "==> FCMPluginActivity onCreate");
Map<String, Object> data = new HashMap<String, Object>();
if (getIntent().getExtras() != null) {
Log.d(TAG, "==> USER TAPPED NOTFICATION");
data.put("wasTapped", true);
for (String key : getIntent().getExtras().keySet()) {
String value = getIntent().getExtras().getString(key);
Log.d(TAG, "\tKey: " + key + " Value: " + value);
data.put(key, value);
}
}
FCMPlugin.sendPushPayload(data);
ShortcutBadger.applyCount(FCMPluginActivity.this, 8);
finish();
forceMainActivityReload();
}
I am importing ShortcutBadger and using it in the onCreate method. The idea is to set the badger when the notification is received; however, this is not working.
Your thoughts and comments are very much appreciated
Set the badge field when you send the notification. The documentation specifies this for ios and based on my test it works, but with some delay. I would also try it for Android, but it may not be possible:
Search for 'badge' here:
https://firebase.google.com/docs/cloud-messaging/http-server-ref

How to make a URL in a balloon notification clickable?

I'm creating a simple IntelliJ Plugin that allows for creating new Pastebin pastes straight from the IDE.
When a paste has been successfully posted to Pastebin, I'd like to display a balloon notification.
Currently the notification is displayed as follows:
final Response<String> postResult = Constants.PASTEBIN.post(paste);
NotificationGroup balloonNotifications = new NotificationGroup("Notification group", NotificationDisplayType.BALLOON, true);
if (postResult.hasError()) {
//Display error notification
} else {
//Display success notification
Notification success = balloonNotifications.createNotification("Successful Paste", "Paste successfully posted!", NotificationType.INFORMATION, null);
Notifications.Bus.notify(success, project);
}
Now, this balloon notification contains the URL to the newly created paste, but unfortunately clicking it does not open the link in a browser. How can that be achieved?
The balloon notification with the URL that should become clickable:
There is NotificationListener which opens urls in notifications: com.intellij.notification.UrlOpeningListener
So you can write:
Notification success = balloonNotifications.createNotification(
"<html>Successful Paste", "Paste successfully posted!</html>",
NotificationType.INFORMATION, new NotificationListener.UrlOpeningListener(true));
After some searching I found the answer myself. It wasn't too difficult actually.
If I instantiate the notification as follows, the link is clickable as was required.
Notification success = balloonNotifications.createNotification("<html>Successful Paste", "Paste successfully posted!</html>", NotificationType.INFORMATION, (notification, hyperlinkEvent) -> {
if (hyperlinkEvent.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
BrowserUtil.browse(hyperlinkEvent.getURL());
}
});
Note: It is also rather useful that the link in the event log is also clickable now.

Cordova Jquery Mobile Local Notification onclick change page

I'm sorry for the long post, but I think this is the only way to explain whats happening... I'm looking for help after a lot of research with no answers... A big problem I think...
So this web app schedule a local notification based on a time picker that the users interact with..
I'm using cordova and jquery mobile multi-page system... It changes from page to page by div IDs, the navigation looks like this: index.html, index.html#page2, index.html#page3..
The local notification is a java plugin for cordova Katzer Local Plugin.
The plugin only works inside the onDeviceReady function and the jquery mobile does not, like this...
document.addEventListener('deviceready', onDeviceReady, false);
/* JQUERY MOBILE HERE */
$(document).on("pagecreate", "#home", function(event) {
$("a#btnpage2").click(function (e) {
e.stopImmediatePropagation();
e.preventDefault();
$( "#page2" ).pagecontainer( "change"); // change to #page2
});
});
$(document).on("pagecreate", "#page2", function(event) {
console.log("#page2 created");
});
function onDeviceReady(){
/* NOTIFICATION PLUGIN HERE */
//create notification
var msg = "notification message";
window.plugin.notification.local.add({
id: 'notif',
date: dateobject,
message: msg,
json: JSON.stringify({ test: msg }),
title: 'Title',
autoCancel: true,
ongoing: false
});
//onclick event notification
window.plugin.notification.local.onclick = function (notif, state, json) {
var msg = JSON.parse(json).test;
$( "#notificationPage" ).pagecontainer( "change", { text: msg} ); //pass data and change to #page2
}
//ontrigger notification
window.plugin.notification.local.ontrigger = function (notif, state, json) {
var msg = JSON.parse(json).test;
}
}
When the notification is fired, and when I click it, it should change the page to #notificationPage.
The problem is that the command inside onclick, does not work even when I click the notification with the app running, it throws this error:
Uncaugh Error: cannot call methods on pagecontainer prior to initialization; attempted to call method 'change'.
However the following command DOES change the page, found it on google: $.mobile.changePage( "#notificationPage" ). But only if the app is running and not interrupted. I think that if its in background or closed even if its not interrupted, it doesn't change the page... it opens the activity defined by the plugin. When I say in background or closed and not interrupted i mean that app was closed by the main button and not the back button that completely closes the app..
I guess this is the classes that handle the notification:
/* Receiver.class notification plugin */
Intent intent = new Intent(context, ReceiverActivity.class)
.putExtra(OPTIONS, options.getJSONObject().toString())
.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
int requestCode = new Random().nextInt();
PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
return notification.setContentIntent(contentIntent);
/* ReceiverActivity.class notification plugin */
Context context = getApplicationContext();
String packageName = context.getPackageName();
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
launchIntent.putExtra("MSG", msgJson); // here I pass the json message to the new intent, thats gonna open when clicking the notification
context.startActivity(launchIntent);
So basically, I want to click the notification, and open a specific page, so I can get the json value on click and pass to that page and then display it to a div element... It seems I can't use the notification plugin commands outside the onDeviceReady, and neither jquery mobile commands inside the onDeviceReady.... Beside that I have to deal with the problem that is to do the same thing if the app is closed and interrupted...
At the java side, I could create another activity along with the main cordova app activity, and create a layout in xml, and add a textview... On the .java file of this new activity I think I could set the setContentView to this xml layout, and set the text of the textView to the json object value I want... this json value is the same as the message of the notification... I pretty sure, like 95% convinced this would work, not tested yet, but the thing is, its hard to maintenance.
What I tried is create this new activity, exactly like the main activity of cordova, but the loadUrl, I set to the page I want to go, not to LaunchUrl, which loads the address from config.xml of cordova, and passed the json value that I added as extra on the intent creation as a url param so on the jquery mobile side I could take the document.URL and the parameter... like this, first I edited the ReceiverActivity.class from notification plugin:
/* ReceiverActivity.class notification plugin */
Context context = getApplicationContext();
//String packageName = context.getPackageName();
Intent launchIntent = new Intent(context, NotificationActivity.class);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
launchIntent.putExtra("MSG", msgJson);
context.startActivity(launchIntent);
/* NotificationActivity.class cordova app second activity */
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
String msg;
Intent intent = getIntent();
Bundle extras = intent.getExtras();
msg = extras.getString("MSG");
String utf_encoded = null;
try {
utf_encoded = URLEncoder.encode(msg,"UTF-8");
} catch (UnsupportedEncodingException e) {}
String url = "file:///android_asset/www/index.html#notificationPage?parameter="+utf_encoded;
super.loadUrl(url);
}
And on the javascript side, I could retrive that parameter in the url:
document.addEventListener('deviceready', onDeviceReady, false);
$( document ).on( "pagebeforechange" , function ( event, data ) {
if ( data.toPage[0].id == "notificationPage" ) {
var url = document.URL;
var urlParams = decodeURIComponent(url);
var onlyParams = urlParams.split('=')[1];
var newchar = " ";
var paramValue = onlyParams.split('+').join(newchar);
$('#notificationPage #showMessage').empty();
$('#notificationPage #showMessage').append("<p>Message: " + paramValue + "</p>");
}
});
function onDeviceReady(){
/* ondeviceready */
}
This actually worked, but it has some bugs... Sometimes the page loads, sometimes the page doesn't load, the page sometimes turned to a black screen... It works specially if the app is closed and interrupted, but if its open, most of the times it goes to a black screen... and if I click the back button on the device, it "navigates back", but it actually goes to the page that should be activated and showing the message... its like the page is behind this black screen sometimes and it won't come out to front unless I use back button..
I'm out of options... tried almost everything with no concrete and stable solution.. Flags, javascript, java, redirect url at javascript, at java, nothing seems to work...
Well I'm not a developer. I'm a designer, putting all my efforts to finish this... but god, its hard.... Theoretically a easy solution would be leaving everything at defaults, and when the plugin "launch" the app or the intent, or whatever by clicking the notification, just run a javascript with the command from jquery mobile that change pages... That would be amazing! hahah
I really need help..
Thanks to everyone that is reading this... To everyone that will try to help me...
Thank you all
Use this method:
cordova.plugins.notification.local.on("click", function (notification) {
alert(notification.text);
}, scope);
Here is the updated doc.
Cordova Jquery Mobile Local Notification onclick change page

How to use Facebook SDK to post article to specific friend's wall? [android]

I was a beginner of facebook SDK.
I have reference the facebook SDK sample inside "HellowFacebookSampleActivity"file
and know how to use Request.newStatusUpdateRequest (post to the user's own Wall)
But I do not know how to use Request.newPostRequest to post article to specific friend's wall and do not know how to use the inside parameters .In particular,I dont know how to use the third GraphObject parameter.
I have been found a lot of information, but because the API has been revised ,so the information could not be used.
Is there some examples or website allows me to accomplish this goal?
Thank you so much!
Here is the code that I want to used to be changed.
private void postStatusUpdate() {
if (user != null && hasPublishPermission()) {
final String message = getString(R.string.status_update, user.getFirstName(), (new Date().toString()));
Request request = Request.newStatusUpdateRequest(Session.getActiveSession(), message, new Request.Callback() {
//Request request = Request.newPostRequest(Session.getActiveSession(), "1000001851621**",GraphObject??? , new Request.Callback() {
#Override
public void onCompleted(Response response) {
showPublishResult(message, response.getGraphObject(), response.getError());
}
});
request.executeAsync();
} else {
pendingAction = PendingAction.POST_STATUS_UPDATE;
}
}
Facebook updated their SDK a few months ago to require you to use a native feed dialog instead of your own method. This makes it so the user has to look at the pre-made facebook window to post anything on another person's wall.
Blog Post

Categories

Resources