Link keyword in TextView to file/directory - android

Is there any way that I can link a keyword in a TextView to a file or directory on the user's SD card? My app produces stack trace files when it crashes and I want the user to able to click a link in my About dialog to view either the latest one or the folder containing all of them. (Something like "If this app crashes, please send [link]the latest stack.trace file[/link] to us at myapp#example.com.")
I know it is possible to use the following code to make a Web link but I tried to modify it to use "file:///sdcard/path/to/file/stack.trace" which causes my app to Force Close when the link is clicked.
<string name="strSample">This is Web link to <a href="http://www.google.com">Google</a>!</string>
final TextView tvSample = (TextView)findViewById(R.id.tvSample);
tvSample.setMovementMethod(LinkMovementMethod.getInstance());
String strSample = getResources().getString(R.string.strSample);
tvSample.setText(Html.fromHtml(strSample));

You can extend your method by replacing Html.fromHtml(strSample) part which returns Spannable. Create your own Spannable and add ClickableSpan to it. In the onClick method you can place whatever logic you need. Here's quick examle that you can extend
public Spannable getProfileLink(final Context context) {
final String name = firstName + " " + lastName;
Spannable spans = SpannableStringBuilder.valueOf(name);
ClickableSpan clickSpan = new ClickableSpan() {
#Override
public void onClick(View widget) {
// TODO - call profile here
Toast.makeText(context, "Will call profile", Toast.LENGTH_LONG);
}
};
spans.setSpan(clickSpan, 0, name.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spans;
}

Related

How to calculate age in Android Application using edit text

I am working on an android application that shows bar specials in the area and I want to make sure the only users that are using our app are 21+ years old. I have created a login/registration activity using edit texts and the information typed into the edit texts is sent to a mySQL database.
I have already searched for tutorials on youtube/stack overflow/google for help on this and I have only found datepicker tutorials. I am not sure how I would implement a datepicker tutorial into my project using edit texts.
Here is part of my RegisterActivity.java file that I want to validate the data when the user clicks on register. I have already figured out how to validate email/password but do not know how to add date difference into my code. I have also added my submitForm function that is called....
I am not sure what the output is supposed to look like or how to implement age validation into my project as a I am still fairly new to using Android Studio and I am open to new ideas etc. on how to best implement this into my project.
Here is part of my RegisterActivity.java file that I want to validate the data when the user clicks on register. I have already figured out how to validate email/password but do not know how to add date difference into my code. I have also added my submitForm function that is called....
buttonSignup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String email = signupInputEmail.getText().toString();
String password = signupInputPassword.getText().toString();
if (password.length()< 8){
signupInputPassword.setError("Your password must be at least 8 characters");
}else if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
signupInputEmail.setError("You must enter a valid email address");
} else {
submitForm();
}
}
});
submitForm()
private void submitForm() {
int selectedId = genderRadioGroup.getCheckedRadioButtonId();
String gender;
if(selectedId == R.id.female_radio_btn)
gender = "Female";
else
gender = "Male";
registerUser(signupInputName.getText().toString(),
signupInputEmail.getText().toString(),
signupInputPassword.getText().toString(),
gender,
signup_input_DOB.getText().toString());
}
Looks like you are following a long way to do this task. You can simply use DatePicker (Android Date Picker Official Docs
and set the selection range for the date, set the selected date (by the user) on the TextView. User Interface for handling the click event.
Create Interface.
public interface IOnItemClickListenerCountryStates {
void onAgeClick(String Date);
}
Convert the date of birth on the sign up input from String to Date like this:
String DOB = signup_input_DOB.getText().toString();
Date dateOfBirth=new SimpleDateFormat("dd/MM/yyyy").parse(DOB);
Then pass the date of birth to a method computing for the age:
int age = currentDate.getYear() - dateOfBirth.getYear();

Android Handle/Override/Interrupt Intent from the same Activity that fired it

I have an android application that has to parse fairly large amounts of HTML and place it inside one or more TextViews. So any one of these given text views might contain one more html link. These links are created dynamically and embedded in the rest of the text. It seems the only way I can allow these links to work is by using the following code.
TextView textView = new TextView(mContext);
textView.setAutoLinkMask(0);
textView.setLinksClickable(true);
Linkify.addLinks(textView, Patterns.WEB_URL, "ref://");
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.append(getSpannable(htmlString));
This works just fine for any http link, I simply added filter to a WebActivity in my a filter in my manifest and call it a day.
My problem however is that I have links that I want to send with additional data not contained in the link itself. Additionally the the extra data I want to send would change based on the target of the link. I cannot do this because the intents are fired based on the HTML data the user clicks.
Is there any way to modify / intercept/ override an Intent fired by my Activity in order to add additional data to it after it has been fired?
Edit With Answer Based on #Tanis.7x Suggestion
In my original question I failed to specify that I was using a Spanned derived from Html.fromHtml(htmlString);
I was able to figured out a solution based on #Tanis.7x answer and this question's accepted answer Android TextView with Clickable Links: how to capture clicks?
TextView textView = new TextView(mContext);
textView.setAutoLinkMask(0);
textView.setLinksClickable(true);
Linkify.addLinks(textView, Patterns.WEB_URL, "ref://");
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.append(getHtmlStringForTextView(Html.fromHtml(htmlString)));
private SpannableStringBuilder getHtmlStringForTextView(String html)
{
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for(URLSpan span : urls) {
makeLinkClickable(strBuilder, span);
}
return strBuilder;
}
private void makeLinkClickable(SpannableStringBuilder spannableStringBuilder, final URLSpan span)
{
int start = spannableStringBuilder.getSpanStart(span);
int end = spannableStringBuilder.getSpanEnd(span);
int flags = spannableStringBuilder.getSpanFlags(span);
ClickableSpan clickable = new ClickableSpan() {
public void onClick(View view) {
//handle click here
}
};
spannableStringBuilder.setSpan(clickable, start, end, flags);
spannableStringBuilder.removeSpan(span);
}
You cannot intercept intents after they are fired.
If you look at the source of URLSpan (which is responsible for handling links in TextViews), you will see that in it's onClick() method it creates an appropriate Intent, then fires it off with a call to context.startActivity(intent);. At that point in time the Intent is out of your hands and responsibility for handling the Intent lies within the Android framework.
You can, however, get the behavior you desire. First you need to create your own URLSpan subclass. Override onClick() and handle the click however you want.
public class CustomUrlSpan extends URLSpan {
public CustomUrlSpan(String url) {
super(url);
}
/* You may want to properly support the ParcelableSpan interface as well */
#Override
public void onClick(View widget) {
Uri uri = Uri.parse(getURL());
Context context = widget.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
// Put your custom intent handling in here
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
}
}
}
Then, instead of using Linkify to make your links clickable, you will need to create the spans yourself. Take a look at the Linkify source if you need a starting point- you'll probably want to do something very similar to addLinks(), but with your CustomUrlSpan instead of the standard URLSpan.

Button Text and Booleans (Simple Android App)

I'm build the Fun Facts app on the Android Development Track. I decided to take a exploratory detour and try to create a very basic introductory message to the user. I changed the factTextView text to "You can click the button below to see a new fact!" and changed the showFactButton text to "Try it out!"
From there, I changed the final line onClick object (is that an object?) to the following:
public void onClick(View view) {
String fact = mFactBook.getFact();
// Update the label with our dynamic fact
factLabel.setText(fact);
// Set button text to new fact prompt
showFactButton.setText("Show another fun fact.");
This seems to work fine. However, I feel like "updating" the button text to the same new string on every press isn't always the best practice, even if it is easy and readable. I tried to add a boolean that will check the text of the button, and update it only if it has not already been updated. This is what I've come up with so far:
View.OnClickListener listener = new View.OnClickListener() {
#Override
public String launchText = getResources().getString(R.string.start_text);
public String nextText = getResources().getString(R.string.next_text);
public String buttonText = (String) showFactButton.getText();
public boolean updateLaunchText() {
if (buttonText.equals(launchText)) {
buttonText.replaceAll(launchText, nextText);
return true;
}
else {
return true;
}
}
public void onClick(View view) {
String fact = mFactBook.getFact();
// Update the label with our dynamic fact
factLabel.setText(fact);
}
};
With the following added to strings.xml:
<string name="start_text">Try it out!</string>
<string name="next_text">Show another Fun Fact!</string>
No errors, but the button text stays on "Try it out!" I'm sure that all the extra objects are totally unnecessary compared to the first, working method for the scope of this app, but I'd still like to figure it out since I don't really have any idea what I'm doing with the boolean.
Questions: 1) What am I missing in the longer boolean approach? 2) What's the actual most efficient approach to accomplish this task?
Did you connect the listener to the button object?Without that connection no logic is applied to a button click.It goes like this:
buttonName.setOnClickListener(...)
You'd have to initialize the button object first though :)
Where r u call to method updateLaunchText() ?
you should change the objects to global object (not to create the into the listener):
private String launchText = getResources().getString(R.string.start_text);
private String nextText = getResources().getString(R.string.next_text);
private String buttonText = (String) showFactButton.getText();
and take the method updateLaunchText() out of the listener too.
and then into the onClick(View view) call to updateLaunchText() like this:
public void onClick(View view) {
updateLaunchText();
String fact = mFactBook.getFact();
// Update the label with our dynamic fact
factLabel.setText(fact);
}

Rewriting the text of a button on every sync

In my app I have a button that has a text and a variable attached to it.. for example - "inbox 20" where 20 is a variable.
Every minute I do a sync on a separate thread and get the new value of the inbox messages.
Whenever I get the new value, I do
b.setText("Inbox" + numMails); //where numMails is an int retrieved from the server.
My question is, is there any way to keep the "Inbox" part static and there forever, and just add the numMails ?
As Button's text cannot be updated partially, it's not possible.
However I assume that you want to achieve this just because of not to rewrite "Inbox " + part.
So you can achieve this by extracting a method like this:
private void setInboxButtonText(int numMails) {
StringBuilder sb = new StringBuilder();
sb.append("Inbox ");
sb.append(String.valueOf(numMails));
b.setText(sb.toString());
}
and use this method wherever you update that Button's text.
Furthermore, if you are looking for more abstract structure then I suggest you to extend android.widget.Button class like this:
public class InboxButton extends Button {
#Override
public void setText(int numMails) {
StringBuilder sb = new StringBuilder();
sb.append("Inbox ");
sb.append(String.valueOf(numMails));
super.setText(sb.toString());
}
}
and use this class while defining your Inbox Button.
You can do this way:
b.setText(b.getText().split(" ")[0] + " " + numMails);

Converting a SpannableString to a ClickableSpan

I am trying to make clickable links in text strings that launch an activity when clicked. I have used Linkify() to detect links in my text. This function is capable of adding links to text, but only web URLs. I need to turn my output into a ClickableSpan so that I can implement this technique.
How do I get Linkify()'s identified links to become ClickableSpans which direct to an activity?
Below is the code I have used in Linkify:
// Linkify parameters
final static Pattern pattern = Pattern.compile("\\[[^]]*]"); // defines the fact that links are bound by [square brackets]
final String scheme = "http://"; // TODO: Currently this is just a blank link
Linkify.addLinks(linkText, pattern, scheme);
For what you want to achieve, it's probably simpler to just override the startActivity() method in your Activity and intercept the ACTION_VIEW intents with the URLs in your text. Something like this:
public class MyActivity extends Activity {
#Override
public void startActivity(Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_VIEW)) {
// launch our other activity instead
Intent ourIntent = new Intent(this, MyOtherActivity.class);
ourIntent.setData(intent.getData());
super.startActivity(ourIntent);
// we're done!
return;
}
// else, normal handling by the framework
super.startActivity(intent);
}
// the rest of your activity code
}
For reference, here's the source code for URLSpan which will trigger the startActivity() method above.
How do I get Linkify()'s identified links to become ClickableSpans which direct to an activity?
After your call to addLinks(), call getText() to retrieve the Spanned object from the TextView. This object will have a series of URLSpan objects, one per matched link -- you can get an array of those through a call to getSpans(). You will need to note where each those spans start and end (via getSpanStart() and getSpanEnd()), remove the URLSpan, and replace it with your own spans to do what you want.

Categories

Resources