use of android.text.style.URLSpan in project Etar-Calendar by Etar-Group.
the class AlertReceiver method buildBasicNotification.
private static Notification buildBasicNotification(Notification.Builder notificationBuilder, Context context, String title, String summaryText, long startMillis, long endMillis, long eventId, int notificationId, boolean doPopup, int priority, boolean addActionButtons) {
Resources resources = context.getResources();
if (title == null || title.length() == 0) {
title = resources.getString(R.string.no_title_label);
}
// Create an intent triggered by clicking on the status icon, that dismisses the
// notification and shows the event.
PendingIntent clickIntent = createClickEventIntent(context, eventId, startMillis, endMillis, notificationId);
// Create a delete intent triggered by dismissing the notification.
PendingIntent deleteIntent = createDeleteEventIntent(context, eventId, startMillis, endMillis, notificationId);
// Create the base notification.
notificationBuilder.setContentTitle(title);
notificationBuilder.setContentText(summaryText);
notificationBuilder.setSmallIcon(R.drawable.stat_notify_calendar);
int color = DynamicTheme.getColorId(DynamicTheme.getPrimaryColor(context));
notificationBuilder.setColor(context.getResources().getColor(color));
notificationBuilder.setContentIntent(clickIntent);
notificationBuilder.setDeleteIntent(deleteIntent);
// Add setting channel ID for Oreo or later
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationBuilder.setChannelId(ALERT_CHANNEL_ID);
}
if (doPopup) {
notificationBuilder.setFullScreenIntent(createAlertActivityIntent(context), true);
}
PendingIntent mapIntent = null, callIntent = null, snoozeIntent = null, emailIntent = null;
if (addActionButtons) {
// Send map, call, and email intent back to ourself first for a couple reasons:
// 1) Workaround issue where clicking action button in notification does
// not automatically close the notification shade.
// 2) Event information will always be up to date.
// Create map and/or call intents.
URLSpan[] urlSpans = getURLSpans(context, eventId);
mapIntent = createMapBroadcastIntent(context, urlSpans, eventId);
callIntent = createCallBroadcastIntent(context, urlSpans, eventId);
// Create email intent for emailing attendees.
emailIntent = createBroadcastMailIntent(context, eventId, title);
// Create snooze intent. TODO: change snooze to 10 minutes.
snoozeIntent = createSnoozeIntent(context, eventId, startMillis, endMillis, notificationId);
}
// Turn off timestamp.
notificationBuilder.setWhen(0);
// Should be one of the values in Notification (ie. Notification.PRIORITY_HIGH, etc).
// A higher priority will encourage notification manager to expand it.
notificationBuilder.setPriority(priority);
// Add action buttons. Show at most three, using the following priority ordering:
// 1. Map
// 2. Call
// 3. Email
// 4. Snooze
// Actions will only be shown if they are applicable; i.e. with no location, map will
// not be shown, and with no recipients, snooze will not be shown.
// TODO: Get icons, get strings. Maybe show preview of actual location/number?
int numActions = 0;
if (mapIntent != null && numActions < MAX_NOTIF_ACTIONS) {
notificationBuilder.addAction(R.drawable.ic_map, resources.getString(R.string.map_label), mapIntent);
numActions++;
}
if (callIntent != null && numActions < MAX_NOTIF_ACTIONS) {
notificationBuilder.addAction(R.drawable.ic_call, resources.getString(R.string.call_label), callIntent);
numActions++;
}
if (emailIntent != null && numActions < MAX_NOTIF_ACTIONS) {
notificationBuilder.addAction(R.drawable.ic_menu_email_holo_dark, resources.getString(R.string.email_guests_label), emailIntent);
numActions++;
}
if (snoozeIntent != null && numActions < MAX_NOTIF_ACTIONS) {
notificationBuilder.addAction(R.drawable.ic_alarm_holo_dark, resources.getString(R.string.snooze_label), snoozeIntent);
numActions++;
}
return notificationBuilder.build();
}
use of android.text.style.URLSpan in project Etar-Calendar by Etar-Group.
the class AlertReceiver method onReceive.
@Override
public void onReceive(final Context context, final Intent intent) {
if (AlertService.DEBUG) {
Log.d(TAG, "onReceive: a=" + intent.getAction() + " " + intent.toString());
}
if (MAP_ACTION.equals(intent.getAction())) {
// Try starting the map action.
// If no map location is found (something changed since the notification was originally
// fired), update the notifications to express this change.
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
if (eventId != -1) {
URLSpan[] urlSpans = getURLSpans(context, eventId);
Intent geoIntent = createMapActivityIntent(context, urlSpans);
if (geoIntent != null) {
// Location was successfully found, so dismiss the shade and start maps.
try {
context.startActivity(geoIntent);
} catch (ActivityNotFoundException exception) {
Toast.makeText(context, context.getString(R.string.no_map), Toast.LENGTH_SHORT).show();
}
closeNotificationShade(context);
} else {
// No location was found, so update all notifications.
// Our alert service does not currently allow us to specify only one
// specific notification to refresh.
AlertService.updateAlertNotification(context);
}
}
} else if (CALL_ACTION.equals(intent.getAction())) {
// Try starting the call action.
// If no call location is found (something changed since the notification was originally
// fired), update the notifications to express this change.
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
if (eventId != -1) {
URLSpan[] urlSpans = getURLSpans(context, eventId);
Intent callIntent = createCallActivityIntent(context, urlSpans);
if (callIntent != null) {
// Call location was successfully found, so dismiss the shade and start dialer.
context.startActivity(callIntent);
closeNotificationShade(context);
} else {
// No call location was found, so update all notifications.
// Our alert service does not currently allow us to specify only one
// specific notification to refresh.
AlertService.updateAlertNotification(context);
}
}
} else if (MAIL_ACTION.equals(intent.getAction())) {
closeNotificationShade(context);
// Now start the email intent.
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
if (eventId != -1) {
Intent i = new Intent(context, QuickResponseActivity.class);
i.putExtra(QuickResponseActivity.EXTRA_EVENT_ID, eventId);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
} else {
Intent i = new Intent();
i.setClass(context, AlertService.class);
i.putExtras(intent);
i.putExtra("action", intent.getAction());
Uri uri = intent.getData();
if (uri != null) {
i.putExtra("uri", uri.toString());
}
beginStartingService(context, i);
}
}
use of android.text.style.URLSpan in project Etar-Calendar by Etar-Group.
the class Utils method extendedLinkify.
/**
* Replaces stretches of text that look like addresses and phone numbers with clickable
* links. If lastDitchGeo is true, then if no links are found in the textview, the entire
* string will be converted to a single geo link. Any spans that may have previously been
* in the text will be cleared out.
* <p>
* This is really just an enhanced version of Linkify.addLinks().
*
* @param text - The string to search for links.
* @param lastDitchGeo - If no links are found, turn the entire string into one geo link.
* @return Spannable object containing the list of URL spans found.
*/
public static Spannable extendedLinkify(String text, boolean lastDitchGeo) {
// We use a copy of the string argument so it's available for later if necessary.
Spannable spanText = SpannableString.valueOf(text);
/*
* If the text includes a street address like "1600 Amphitheater Parkway, 94043",
* the current Linkify code will identify "94043" as a phone number and invite
* you to dial it (and not provide a map link for the address). For outside US,
* use Linkify result iff it spans the entire text. Otherwise send the user to maps.
*/
String defaultPhoneRegion = System.getProperty("user.region", "US");
if (!defaultPhoneRegion.equals("US")) {
Linkify.addLinks(spanText, Linkify.ALL);
// If Linkify links the entire text, use that result.
URLSpan[] spans = spanText.getSpans(0, spanText.length(), URLSpan.class);
if (spans.length == 1) {
int linkStart = spanText.getSpanStart(spans[0]);
int linkEnd = spanText.getSpanEnd(spans[0]);
if (linkStart <= indexFirstNonWhitespaceChar(spanText) && linkEnd >= indexLastNonWhitespaceChar(spanText) + 1) {
return spanText;
}
}
// Otherwise, to be cautious and to try to prevent false positives, reset the spannable.
spanText = SpannableString.valueOf(text);
// If lastDitchGeo is true, default the entire string to geo.
if (lastDitchGeo && !text.isEmpty()) {
Linkify.addLinks(spanText, mWildcardPattern, "geo:0,0?q=");
}
return spanText;
}
/*
* For within US, we want to have better recognition of phone numbers without losing
* any of the existing annotations. Ideally this would be addressed by improving Linkify.
* For now we manage it as a second pass over the text.
*
* URIs and e-mail addresses are pretty easy to pick out of text. Phone numbers
* are a bit tricky because they have radically different formats in different
* countries, in terms of both the digits and the way in which they are commonly
* written or presented (e.g. the punctuation and spaces in "(650) 555-1212").
* The expected format of a street address is defined in WebView.findAddress(). It's
* pretty narrowly defined, so it won't often match.
*
* The RFC 3966 specification defines the format of a "tel:" URI.
*
* Start by letting Linkify find anything that isn't a phone number. We have to let it
* run first because every invocation removes all previous URLSpan annotations.
*
* Ideally we'd use the external/libphonenumber routines, but those aren't available
* to unbundled applications.
*/
boolean linkifyFoundLinks = Linkify.addLinks(spanText, Linkify.ALL & ~(Linkify.PHONE_NUMBERS));
/*
* Get a list of any spans created by Linkify, for the coordinate overlapping span check.
*/
URLSpan[] existingSpans = spanText.getSpans(0, spanText.length(), URLSpan.class);
/*
* Check for coordinates.
* This must be done before phone numbers because longitude may look like a phone number.
*/
Matcher coordMatcher = COORD_PATTERN.matcher(spanText);
int coordCount = 0;
while (coordMatcher.find()) {
int start = coordMatcher.start();
int end = coordMatcher.end();
if (spanWillOverlap(spanText, existingSpans, start, end)) {
continue;
}
URLSpan span = new URLSpan("geo:0,0?q=" + coordMatcher.group());
spanText.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
coordCount++;
}
/*
* Update the list of existing spans, for the phone number overlapping span check.
*/
existingSpans = spanText.getSpans(0, spanText.length(), URLSpan.class);
/*
* Search for phone numbers.
*
* Some URIs contain strings of digits that look like phone numbers. If both the URI
* scanner and the phone number scanner find them, we want the URI link to win. Since
* the URI scanner runs first, we just need to avoid creating overlapping spans.
*/
int[] phoneSequences = findNanpPhoneNumbers(text);
/*
* Insert spans for the numbers we found. We generate "tel:" URIs.
*/
int phoneCount = 0;
for (int match = 0; match < phoneSequences.length / 2; match++) {
int start = phoneSequences[match * 2];
int end = phoneSequences[match * 2 + 1];
if (spanWillOverlap(spanText, existingSpans, start, end)) {
continue;
}
/*
* The Linkify code takes the matching span and strips out everything that isn't a
* digit or '+' sign. We do the same here. Extension numbers will get appended
* without a separator, but the dialer wasn't doing anything useful with ";ext="
* anyway.
*/
// String dialStr = phoneUtil.format(match.number(),
// PhoneNumberUtil.PhoneNumberFormat.RFC3966);
StringBuilder dialBuilder = new StringBuilder();
for (int i = start; i < end; i++) {
char ch = spanText.charAt(i);
if (ch == '+' || Character.isDigit(ch)) {
dialBuilder.append(ch);
}
}
URLSpan span = new URLSpan("tel:" + dialBuilder.toString());
spanText.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
phoneCount++;
}
/*
* If lastDitchGeo, and no other links have been found, set the entire string as a geo link.
*/
if (lastDitchGeo && !text.isEmpty() && !linkifyFoundLinks && phoneCount == 0 && coordCount == 0) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "No linkification matches, using geo default");
}
Linkify.addLinks(spanText, mWildcardPattern, "geo:0,0?q=");
}
return spanText;
}
use of android.text.style.URLSpan in project Android-Developers-Samples by johnjohndoe.
the class MainActivity method onCreate.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_main);
// BEGIN_INCLUDE(text_auto_linkify)
/*
* text_auto_linkify shows the android:autoLink property, which
* automatically linkifies things like URLs and phone numbers
* found in the text. No java code is needed to make this
* work.
* This can also be enabled programmatically by calling
* .setAutoLinkMask(Linkify.ALL) before the text is set on the TextView.
*
* See android.text.util.Linkify for other options, for example only
* auto-linking email addresses or phone numbers
*/
// END_INCLUDE(text_auto_linkify)
// BEGIN_INCLUDE(text_html_resource)
/*
* text_html_resource has links specified by putting anchor tags (<a>) in the string
* resource. By default these links will appear but not
* respond to user input. To make them active, you need to
* call setMovementMethod() on the TextView object.
*/
TextView textViewResource = (TextView) findViewById(R.id.text_html_resource);
textViewResource.setText(Html.fromHtml(getResources().getString(R.string.link_text_manual)));
textViewResource.setMovementMethod(LinkMovementMethod.getInstance());
// END_INCLUDE(text_html_resource)
// BEGIN_INCLUDE(text_html_program)
/*
* text_html_program shows creating text with links from HTML in the Java
* code, rather than from a string resource. Note that for a
* fixed string, using a (localizable) resource as shown above
* is usually a better way to go; this example is intended to
* illustrate how you might display text that came from a
* dynamic source (eg, the network).
*/
TextView textViewHtml = (TextView) findViewById(R.id.text_html_program);
textViewHtml.setText(Html.fromHtml("<b>text_html_program: Constructed from HTML programmatically.</b>" + " Text with a <a href=\"http://www.google.com\">link</a> " + "created in the Java source code using HTML."));
textViewHtml.setMovementMethod(LinkMovementMethod.getInstance());
// END_INCLUDE(text_html_program)
// BEGIN_INCLUDE(text_spannable)
/*
* text_spannable illustrates constructing a styled string containing a
* link without using HTML at all. Again, for a fixed string
* you should probably be using a string resource, not a
* hardcoded value.
*/
SpannableString ss = new SpannableString("text_spannable: Manually created spans. Click here to dial the phone.");
/*
* Make the first 38 characters bold by applying a StyleSpan with bold typeface.
*
* Characters 45 to 49 (the word "here") is made clickable by applying a URLSpan
* pointing to a telephone number. Clicking it opens the "tel:" URL that starts the dialer.
*
* The SPAN_EXCLUSIVE_EXCLUSIVE flag defines this span as exclusive, which means
* that it will not expand to include text inserted on either side of this span.
*/
ss.setSpan(new StyleSpan(Typeface.BOLD), 0, 39, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ss.setSpan(new URLSpan("tel:4155551212"), 40 + 6, 40 + 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
TextView textViewSpan = (TextView) findViewById(R.id.text_spannable);
textViewSpan.setText(ss);
/*
* Set the movement method to move between links in this TextView.
* This means that the user traverses through links in this TextView, automatically
* handling appropriate scrolling and key commands.
*/
textViewSpan.setMovementMethod(LinkMovementMethod.getInstance());
// END_INCLUDE(text_spannable)
}
use of android.text.style.URLSpan in project Knife by mthli.
the class KnifeText method switchToKnifeStyle.
protected void switchToKnifeStyle(Editable editable, int start, int end) {
BulletSpan[] bulletSpans = editable.getSpans(start, end, BulletSpan.class);
for (BulletSpan span : bulletSpans) {
int spanStart = editable.getSpanStart(span);
int spanEnd = editable.getSpanEnd(span);
spanEnd = 0 < spanEnd && spanEnd < editable.length() && editable.charAt(spanEnd) == '\n' ? spanEnd - 1 : spanEnd;
editable.removeSpan(span);
editable.setSpan(new KnifeBulletSpan(bulletColor, bulletRadius, bulletGapWidth), spanStart, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
QuoteSpan[] quoteSpans = editable.getSpans(start, end, QuoteSpan.class);
for (QuoteSpan span : quoteSpans) {
int spanStart = editable.getSpanStart(span);
int spanEnd = editable.getSpanEnd(span);
spanEnd = 0 < spanEnd && spanEnd < editable.length() && editable.charAt(spanEnd) == '\n' ? spanEnd - 1 : spanEnd;
editable.removeSpan(span);
editable.setSpan(new KnifeQuoteSpan(quoteColor, quoteStripeWidth, quoteGapWidth), spanStart, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
URLSpan[] urlSpans = editable.getSpans(start, end, URLSpan.class);
for (URLSpan span : urlSpans) {
int spanStart = editable.getSpanStart(span);
int spanEnd = editable.getSpanEnd(span);
editable.removeSpan(span);
editable.setSpan(new KnifeURLSpan(span.getURL(), linkColor, linkUnderline), spanStart, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
Aggregations