I have some text in my application that says in case you need extra help, please email us and here is the email address, blah, blah.
But I want them to be able to click the email link and have their email client open. Is that possible? Or is that bad practice?
If it is reasonable practice, how can it be done?
This is a very reasonable request and the Linkify class will turn every email address into an appropriate link for you. Simply add the autoLink attribute to your XML:
<TextView
...
android:autoLink="email" />
You can make your text clickable by using setOnClickListener on the text
textView.setOnClickListener(new View.OnClickListener());
You can open the email client by creating a new Intent with the ACTION_SEND. Settype, the email address and subject like this:
Intent emailintent = new Intent(android.content.Intent.ACTION_SEND);
emailintent.setType("plain/text");
emailintent.putExtra(android.content.Intent.EXTRA_EMAIL,new String[] {"mailk#gmail.com" });
emailintent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
emailintent.putExtra(android.content.Intent.EXTRA_TEXT,"");
startActivity(Intent.createChooser(emailintent, "Send mail..."));
You need to fire an intent in your onClickListener:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain"); // send email as plain text
intent.putExtra(Intent.EXTRA_EMAIL, new String[] { "some#email.address" });
intent.putExtra(Intent.EXTRA_SUBJECT, "subject");
intent.putExtra(Intent.EXTRA_TEXT, "mail body");
startActivity(Intent.createChooser(intent, ""));
Please be aware of a little bug from API 24 onwards which makes the accepted solution not work if the local part of the email address has exactly 2 characters like "it#google.com".
See the issue: https://issuetracker.google.com/issues/64435698
Allegedly fixed already, but apparently not rolled out yet.
(Don't you love it that they know about the issue and don't even bother to update the documentation accordingly? https://developer.android.com/reference/android/widget/TextView.html#attr_android:autoLink)
So unless you're sure that you're not dealing with such 2-letter email addresses, you should rather use the accepted approach from here for the time being:
TextView to send email when clicked
Take care to remove the autolink attribute from the TextView then.
The accepted answer may work for emails but if you want to detect different patterns like emails, contact numbers, weblink and set a separate on click implementations for these patterns I suggest you to use CustomClickableEmailPhoneTextview
Sample Code to use the library.
CustomPartialyClickableTextview customPartialyClickableTextview= (CustomPartialyClickableTextview) findViewById(R.id.textViewCustom);
/**
* Create Objects For Click Patterns
*/
ClickPattern email=new ClickPattern();
ClickPattern phone=new ClickPattern();
ClickPattern weblink=new ClickPattern();
/**
* set Functionality for what will happen on click of that pattern
* In this example pattern is email
*/
email.setOnClickListener(new ClickPattern.OnClickListener() {
#Override
public void onClick() {
Toast.makeText(MainActivity.this,"email clicked",Toast.LENGTH_LONG).show();
}
});
/**
* set Functionality for what will happen on click of that pattern
* In this example pattern is phone
*/
phone.setOnClickListener(new ClickPattern.OnClickListener() {
#Override
public void onClick() {
Toast.makeText(MainActivity.this,"phone clicked",Toast.LENGTH_LONG).show();
}
});
/**
* set Functionality for what will happen on click of that pattern
* In this example pattern is weblink
*/
weblink.setOnClickListener(new ClickPattern.OnClickListener() {
#Override
public void onClick() {
Toast.makeText(MainActivity.this,"website clicked",Toast.LENGTH_LONG).show();
}
});
/**
* set respective regex string to be used to identify patter
*/
email.setRegex("\\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,4}\\b"); // regex for email
phone.setRegex("[1-9][0-9]{9,14}"); // regex for phone number
weblink.setRegex("^(https?|ftp|file)://[-a-zA-Z0-9+&##/%?=~_|!:,.;]*[-a-zA-Z0-9+&##/%=~_|]"); // regex for weblink
/**
* add click pattern to the custom textview - first parameter is tag for reference second parameter is ClickPattern object
*/
customPartialyClickableTextview.addClickPattern("email",email);
customPartialyClickableTextview.addClickPattern("phone",phone);
customPartialyClickableTextview.addClickPattern("weblink",weblink);
Related
I am creating an android application wherein I have mentioned the phone number, email, website of the business similar to the screenshot of google maps as attached.
Just like in the g maps where
Single click makes an intent to the respective app (opens dialer with phone number copied) etc.
Long Click/Press & hold will copy the number to clipboard displaying a toast that "Phone number is copied to clicpboard".
Now I have set up the intents properly and they are working fine --> step-1 achieved.
When I try to display the toast using "OnLongClickListener" method it is taking quite some time to display the toast message. Is there any way we can speed this up or am I missing something or should I use some other alternative like onTouch() method?
(Stuck with this, yet to learn and try out copying to clipboard thing. Inputs in this regards are also welcome!)
In the g maps app, the toast message appears almost instantly on press & hold. So the same is to be achieved.
The code extract from MainActivity.java (The website, phone number, email id are text views with drawableLeft. And I found out that we cannot use setOnItemLongClick on TextView as it is only for ListView)
// This method is called when the website text view is clicked and opens the compnay website
public void openWebsite(View v) {
TextView textView = (TextView) findViewById(R.id.webURL_text_view);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent openWebsiteIntent = new Intent(Intent.ACTION_VIEW);
openWebsiteIntent.setData(Uri.parse("https://www.company.com"));
if (openWebsiteIntent.resolveActivity(getPackageManager()) != null) {
startActivity(openWebsiteIntent);
}
}
});
textView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
showMessage();
return true;
}
});
}
public void showMessage(){
Toast.makeText(this,"Information copied to Clipboard", Toast.LENGTH_LONG).show();
}
I am new to android development and just trying out something, so please be as elaborative as possible. Thank You.
I've seen strange crash reports from my app.
android.view.accessibility.CaptioningManager$1.onChange (CaptioningManager.java:226)
android.database.ContentObserver.onChange (ContentObserver.java:145)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:703)
http://crashes.to/s/db9e325f0f5
It looks like that there is a problem when accessibility functions are enabled. But how I can detect on what UI element or screen that error appears?
I tried to enable accessibility on my own device and navigate through all application screens, but don't receive an exeption.
EDIT
Can this error be caused by using Span in TextView?
// welcome text
TextView welcome = (TextView) view.findViewById(R.id.home_user_name);
welcome.setText(Html.fromHtml(getString(R.string.home_welcome_text, accountManager.getActiveUser())));
// change...
welcome.append(" ");
SpannableString str = SpannableString.valueOf(getString(R.string.home_user_change));
str.setSpan(new URLSpan(getString(R.string.home_user_change)) {
#Override
public void onClick(View view) {
mGuiHandler.sendEmptyMessage(MESSAGE_CHANGE_USER);
}
}, 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
welcome.append(str);
welcome.setMovementMethod(LinkMovementMethod.getInstance());
First, this isn't part of the accessibility service APIs. It is part of the View's implementation of accessibility. See the google code project. CaptioningManager is in the core/java/android/view/accessibility package. So, this crash is happening regardless of whether accessibility is on or not, or the very least, independent of what accessibility service may be on.
In Captioning Manager on line 235 (the version on Google Code is out of date, but pretty close.). The onChange function is like this:
#Override
public void onChange(boolean selfChange, Uri uri) {
final String uriPath = uri.getPath();
final String name = uriPath.substring(uriPath.lastIndexOf('/') + 1);
if (Secure.ACCESSIBILITY_CAPTIONING_ENABLED.equals(name)) {
notifyEnabledChanged();
} else if (Secure.ACCESSIBILITY_CAPTIONING_LOCALE.equals(name)) {
notifyLocaleChanged();
} else if (Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE.equals(name)) {
notifyFontScaleChanged();
} else {
// We only need a single callback when multiple style properties
// change in rapid succession.
mHandler.removeCallbacks(mStyleChangedRunnable);
mHandler.post(mStyleChangedRunnable);
}
}
This is being called by the ContentObserver class, from this point:
/**
* Dispatches a change notification to the observer. Includes the changed
* content Uri when available and also the user whose content changed.
*
* #param selfChange True if this is a self-change notification.
* #param uri The Uri of the changed content, or null if unknown.
* #param userId The user whose content changed. Can be either a specific
* user or {#link UserHandle#USER_ALL}.
*
* #hide
*/
public void onChange(boolean selfChange, Uri uri, int userId) {
onChange(selfChange, uri);
}
Notice in the documentation for the ContentObserver class explicitly states that the uri can be null, but the CaptioningManager immediately calls getPath without checking fi the value is null. This is why it is crashing. The uri passed to onChange is null.
Now, this is where it gets a little fuzzy right. The rest is private, not available on Google Code. SO, we can only guess as to what zygote is doing. Although, it likely wouldn't be helpful, even if we could see it.
Now, what can we glean from this. In the documentation for the CaptioningManager we see the following explanation for its purpose:
Contains methods for accessing and monitoring preferred video
captioning state and visual properties.
So, based on all of this, check any URIs or other properties of any video and perhaps other media elements in your application...
In my app if any number is set then on clicking it starts a call on that number, and if any website link is given then also it shows that underline and on clicking that it opens the browser.
Similarly, I want to open the email client if any email address is set in the textview and show it underline.
Here you will get about patterns.
Initially when the screen starts you need to check for the type of value and then set the styles and click functions for your TextView like below. I guess you know about how to send emails, make calls and open a web browser with a link. I have made three click listeners but using one is good. You can have a flags for that and depending on that you can make operations instead.
public void setStyleAndFunction(CharSequence target) {
if(Patterns.EMAIL_ADDRESS.matcher(target).matches()) {
textview.setonClickListener() {
// send email
}
}
if(Patterns.PHONE.matcher(target).matches()) {
textview.setonClickListener() {
// make call
}
}
if(Patterns.WEB_URL.matcher(target).matches()) {
//set style (underline)
textview.setonClickListener() {
//open a web browser
}
}
}
Try It works for me :
Just write this code TextView ClickEvent or set as Linkify and call this.
Intent i2 = new Intent(android.content.Intent.ACTION_SEND);
i2.setType("text/html");
i2.putExtra(Intent.EXTRA_CC,new String[]{"Your CC Mail ID"});
i2.putExtra(Intent.EXTRA_EMAIL , new String[]{"Your TO Mail ID"});
i2.putExtra(android.content.Intent.EXTRA_SUBJECT, "Your Mail Body");
I am relatively new to Android programming, but have had experience in Java and other coding languages. As part of a program that I am currently making, I want to be able to send a pre-defined email when a button is pressed. I am currently looking at this code:
Sending Email in Android using JavaMail API without using the default/built-in app
I am currently able to start an intent to start the MailSenderActivity.class. However, I am not able to understand how that is able to send an email through the GmailSender.class. I believe that I am misunderstanding how to use the code provided. Am I supposed to create two separate intents that will start both activities up, one after each other, in the code on the home page, as below? If not, how would I do it?
public void SendEmail(View v) {
Intent i = new Intent(getBaseContext(), MailSenderActivity.class);
Intent j = new Intent(getBaseContext(), GMailSender.class);
startActivity(i);
}
Also, I am wondering about the defined spaces for to/from, subject, body and the like in the code. I see that the MailSenderActivity.class has
try {
GMailSender sender = new GMailSender("username#gmail.com", "password");
sender.sendMail("This is Subject",
"This is Body",
"user#gmail.com",
"user#yahoo.com");
Are the user#gmail.com and user#yahoo.com both the recipients of the email? And are there any other places in the code where I am supposed to define the contents of the email?
Thanks for your time.
Scroll down and read the rest of the answer, you'll see that the sendMail() method gives all the clues:
public synchronized void sendMail(String subject, String body, String sender, String recipients)
So:
"user#gmail.com" is the sender (From field).
"user#yahoo.com" is the recipient (To field). You can specify more with commas, eg
"user#yahoo.com,user_2#gmail.com"
You would also see that GMailSender is just a class, not an Activity. Therefore, it does not need an Intent; just instantiate the class. Also, MailSenderActivity is a code sample demonstrating the implementation of GMailSender. You do not have to use it.
Eg
public void SendMail (View v) {
try {
GMailSender sender = new GMailSender("your_username#gmail.com", "password");
sender.sendMail("Subject",
"Email body",
"Fromfield#gmail.com",
"toField#example.com");
} catch (Exception e) {
Log.e("SendMail", e.getMessage(), e);
}
}
Also keep in mind Java naming conventions state that methods should start with a lowercase letter. You should adhere to those conventions and refactor your code appropriately.
I am invoking a mail intent in
ImageButton mail=(ImageButton)findViewById(R.id.mailgps);
mail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setContentView(R.layout.mail);
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
// TODO Auto-generated method stub
emailIntent.setType("text/plain");
String emailto[]={"myemail"};
String subject="GPS User Report";
String body="Welcome to Samarth Reporting service.Did you see an untracked Dustbin\n.A dustbin not at the right place??\nWant to suggest placement of a dustbin here.\nGo ahead we are all ears.\n.Your present location is\n Latitude: ";
body=body + "28.67890" + " and Longitudes: " + "79.78965";
body=body + "\n\nTell us more.";
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL,emailto);
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,subject);
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT,body);
startActivity(emailIntent);
}
});
and getting the screen like this which ignores the EXTRA_EMAIL attribute as well as EXTRA_SUBJECT and then the body appears at the very bottom.How can I rectify this.??
Well it was a pretty stupid thing.
As earlier I was using another AVD I had the email client setup so it worked nicely.But on the new AVD I overlooked that.So "first" setup the email client then go for invoking intent.
Nonetheless the system should have a better way of handling such situations rather than showing a weird blank screen.