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.
Related
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.
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.
Hello all i wrote an application grabbing photos from facebook. I did that successfully. Now i wrote a notification service using SNS in java. Basically sending out subscription for first time users who log into my application and also when a pictured has been deleted from the repository. My first problem is when i download the pics and user info from facebook, i want to check if its a new user or not. If a new user send out a subscription and if not(basically user exist in mongoDb dont send out email for subscription) but my code keeps sending out email to everyuser. And lastly when a user deletes a photo they get a notification but when i tested it i failed to get an email. Below is my code could someone tell me what im doing wrong.
public class EmailNotifications {
private static final String accessKey = "****************";
private static final String secretAccess ="***********************";
//Notification when user gets info from facebook app for first time.
public static void SignUP(String email, String Topic){
AmazonSNSClient snsClient = new AmazonSNSClient(new BasicAWSCredentials(accessKey, secretAccess));
snsClient.setRegion(Region.getRegion(Regions.US_WEST_1));
//create a Topic
CreateTopicRequest createTopicRequest = new CreateTopicRequest().withName(Topic);
CreateTopicResult createTopicResult = snsClient.createTopic(createTopicRequest);
//subscribes to a topic
SubscribeRequest subscribeRequest = new SubscribeRequest().withTopicArn(createTopicResult.getTopicArn())
.withProtocol("email").withEndpoint(email);
snsClient.subscribe(subscribeRequest);
}
//Notification when photo is deleted
public static void deletePic(String email, String topic, String message){
AmazonSNSClient snsClient = new AmazonSNSClient(new BasicAWSCredentials(accessKey,secretAccess));
snsClient.setRegion(Region.getRegion(Regions.US_WEST_1));
CreateTopicRequest create = new CreateTopicRequest(topic);
CreateTopicResult result = snsClient.createTopic(create);
System.out.println(result);
//String msg = "My text published to SNS topic with email endpoint";
PublishRequest publishRequest = new PublishRequest(result.getTopicArn(), message);
publishRequest.setSubject("Deleted Pic");
/*PublishResult pu= */snsClient.publish(publishRequest);
}
}
Below is my implementation of both delete and grabbing data for first assuming mongodb is empty:
Delete photo implementation:
#Override
//deletes photo from mongoDB... but doesn't send out an email stating phootid
public String deletePhoto(String id, String PhotoId){
String mssg="";
if(accountRepo.exists(id)){
UserAccounts userAccounts=accountRepo.findById(id);
UserPhotos photos = photoRepo.findByPhotoId(PhotoId);
mssg="The picture "+photos.getPhotoId()+" has been deleted from the application";
EmailNotifications.deletePic(userAccounts.getEmail(),topic,mssg);
photoRepo.delete(PhotoId);
return "Photo is deleted";
}
else
return "Photo does not exist";
}
Grabbing photo from face for the first time. The user should get only one notification max. But i keep getting several messages.
#Override
public UserAccounts create(FacebookClient facebookClient){
User me = facebookClient.fetchObject("me", User.class);
UserAccounts userAccounts = new UserAccounts();
userAccounts.setEmail(me.getEmail());
userAccounts.setGender(me.getGender());
userAccounts.setId(me.getId());
userAccounts.setName(me.getName());
accountRepo.save(userAccounts);
EmailNotifications.SignUP(me.getEmail(), topic);
return userAccounts;
}
Could some one assist me on this
Judging by your description and the code, it would guess the email you keep getting when you download for a user is the subscription confirmation email because all EmailNotifications.SignUp does is subscribe the email address.
I would guess that the reason you haven't getting any email when you delete a picture is because you haven't confirmed the subscription. In the subscription confirmation emails, there should be a link you can click on to confirm the subscription.
As for why you keep getting the email every time you download, I can't tell from your code, but in the create method you show there is not if block around calling SignUp to check if the user already existed, which I imagine is your problem.
As an aside, if your application is interacting with users and you want a good email experience, you would probably be better off using SES, which allows you to completely control the formatting and branding of your email.
I know that System.out.println() does not work on Android.
So I need another way to print out some text.
Please help me.
I'm using the Root Tools library
class superuser {
public static Command c ;{
if (RootTools.isRootAvailable()) {
System.out.print("Root found!!");
}
else{ System.out.print(("NO ROOT!"));
}
}
}
Outputing text in android
There are many ways, but usually for testing and debugging processes we use log. The log is not visible to user but you can see it in DDMS.
From what i understand you want to create a dialog or display a textview to users so they know if root is available or not.
1.Logging(for testing and debugging processes)
we defined TAG in below code because it would be easy to make changes later and our code is more organised
private static final String TAG = MyActivity.class.getName();
Log.v(TAG , "here is the line i want to output in logcat");
here v in log.v stands for verbose.You may use i for info, e for error etc.
2.Displaying text to user via a TextView
First lets import the textview. Let the id of the textview you imported may be "resultTextView"
TextView resultText = (TextView) findViewById(R.id.resultTextView);
now applying your logic and setting its text...
if (RootTools.isRootAvailable()) {
resultText.setText("Root found!!");
}
else{ resultText.setText(("NO ROOT!"));
}
3.Creating a dialog
Dialogs are the pop out messages we get.
I would recommend creating a function that takes String message and a String Title as a parameter and creates a dialog using dialog.builder something like this rather than a dialog fragment(which is available in the below link) - http://developer.android.com/reference/android/app/AlertDialog.Builder.html
public void alertDialog(String message,String title){
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
this);
// set title
alertDialogBuilder.setTitle(title);
// set dialog message
alertDialogBuilder
.setMessage(message)
.setPositiveButton("OK", null) //we write null cause we don't want
//to perform any action after ok is clicked, we just want the message to disappear
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
Now you can call the method with title and text you want :)
if(condition){
Log.d("message","The root found");
}
else{
Log.d("message","The root not found");
}
Have you tried using logcat ? http://developer.android.com/reference/android/util/Log.html
use it like so: Log.v("myAwesomeApp", "my developer comment");
then use the log panel in your IDE to read it
Using logcat is the usual way in Android, and the simplest.
Log.d("message_id","message content");
If you want another way to display log, you can try
https://github.com/orhanobut/logger
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