List of usage examples for android.text.style StyleSpan StyleSpan
public StyleSpan(@NonNull Parcel src)
From source file:org.awesomeapp.messenger.ui.MessageListItem.java
private CharSequence formatPresenceUpdates(String contact, int type, Date date, boolean isGroupChat, boolean scrolling) { String body;//from w w w. j a v a 2s . c o m Resources resources = getResources(); switch (type) { case Imps.MessageType.PRESENCE_AVAILABLE: body = resources.getString(isGroupChat ? R.string.contact_joined : R.string.contact_online, contact); break; case Imps.MessageType.PRESENCE_AWAY: body = resources.getString(R.string.contact_away, contact); break; case Imps.MessageType.PRESENCE_DND: body = resources.getString(R.string.contact_busy, contact); break; case Imps.MessageType.PRESENCE_UNAVAILABLE: body = resources.getString(isGroupChat ? R.string.contact_left : R.string.contact_offline, contact); break; default: return null; } body += " - "; body += formatTimeStamp(date, type, null, EncryptionState.NONE, null); if (scrolling) { return body; } else { SpannableString spanText = new SpannableString(body); int len = spanText.length(); spanText.setSpan(new StyleSpan(Typeface.ITALIC), 0, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spanText.setSpan(new RelativeSizeSpan((float) 0.8), 0, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return spanText; } }
From source file:org.miaowo.miaowo.util.Html.java
private static void endHeading(Editable text) { // RelativeSizeSpan and StyleSpan are CharacterStyles // Their ranges should not include the newlines at the end Heading h = getLast(text, Heading.class); if (h != null) { setSpanFromMark(text, h, new RelativeSizeSpan(HEADING_SIZES[h.mLevel]), new StyleSpan(Typeface.BOLD)); }//from w ww. ja v a2 s .c o m endBlockElement(text); }
From source file:com.juick.android.JuickMessagesAdapter.java
private static void setStyleSpans(SpannableStringBuilder ssb, int ssbOffset, Object what, String styleChar) { String txt;/*from www . j a v a2 s. co m*/ txt = ssb.subSequence(ssbOffset, ssb.length()).toString(); txt = " " + txt + " "; ssbOffset -= 1; // int scan = 0; int cnt = 0; while (cnt++ < 20) { // don't need bugs in production. int ix = txt.indexOf(styleChar, scan); if (ix < 0) break; if (" \n".indexOf(txt.charAt(ix - 1)) != -1) { int ix2 = txt.indexOf(styleChar, ix + 1); if (ix2 < 0) break; if (" \n".indexOf(txt.charAt(ix2 + 1)) == -1 // not ends with space || txt.substring(ix, ix2).indexOf("\n") != -1) { // spans several lines scan = ix2; // not ok continue; } else { CharacterStyle span = null; CharacterStyle span2 = null; // found needed stuff if (what instanceof Integer && (((Integer) what) == Typeface.BOLD)) { span = new StyleSpan(Typeface.BOLD); if (helvNueFonts) { span2 = new CustomTypefaceSpan("", JuickAdvancedApplication.helvNueBold); } } if (what instanceof Integer && (((Integer) what) == Typeface.ITALIC)) { span = new StyleSpan(Typeface.ITALIC); } if (what == UnderlineSpan.class) { span = new UnderlineSpan(); } if (span != null && ix2 - ix > 1) { ssb.delete(ssbOffset + ix, ssbOffset + ix + 1); // delete styling char txt = stringDelete(txt, ix, ix + 1); ix2--; // moves, too ssb.delete(ssbOffset + ix2, ssbOffset + ix2 + 1); // second char deleted txt = stringDelete(txt, ix2, ix2 + 1); ssb.setSpan(span, ssbOffset + ix, ssbOffset + ix2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); if (span2 != null) { ssb.setSpan(span2, ssbOffset + ix, ssbOffset + ix2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } scan = ix2; } } } }
From source file:org.sirimangalo.meditationplus.ActivityMain.java
private void populateOnline(JSONArray onlines) { if (onlines.length() == 0) { onlineList.setVisibility(View.GONE); return;// ww w . ja va 2 s . c om } onlineList.setVisibility(View.VISIBLE); ArrayList<JSONObject> onlineArray = new ArrayList<JSONObject>(); ArrayList<String> onlineNamesArray = new ArrayList<String>(); // collect into array for (int i = 0; i < onlines.length(); i++) { try { JSONObject a = onlines.getJSONObject(i); onlineArray.add(a); onlineNamesArray.add(a.getString("username")); } catch (JSONException e) { e.printStackTrace(); } } String text = getString(R.string.online) + " "; // add spans int pos = text.length(); // start after "Online: " text += TextUtils.join(", ", onlineNamesArray); Spannable span = new SpannableString(text); span.setSpan(new StyleSpan(Typeface.BOLD), 0, pos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // bold the "Online: " Drawable android = context.getResources().getDrawable(R.drawable.android); android.setBounds(0, 0, 48, 32); for (JSONObject oneOnA : onlineArray) { try { final String oneOn = oneOnA.getString("username"); int end = pos + oneOn.length(); boolean isMed = false; for (int j = 0; j < jsonList.length(); j++) { JSONObject user = jsonList.getJSONObject(j); String username = user.getString("username"); if (username.equals(oneOn)) isMed = true; } if (oneOnA.getString("source").equals("android")) { ImageSpan image = new ImageSpan(android, ImageSpan.ALIGN_BASELINE); span.setSpan(image, pos - 1, pos, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); } ClickableSpan clickable = new ClickableSpan() { @Override public void onClick(View widget) { showProfile(oneOn); } }; span.setSpan(clickable, pos, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); span.setSpan(new UnderlineSpan() { public void updateDrawState(TextPaint tp) { tp.setUnderlineText(false); } }, pos, end, 0); span.setSpan(new ForegroundColorSpan(isMed ? 0xFF009900 : 0xFFFF9900), pos, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); pos += oneOn.length() + 2; } catch (JSONException e) { e.printStackTrace(); } } onlineList.setText(span); onlineList.setMovementMethod(LinkMovementMethod.getInstance()); }
From source file:org.getlantern.firetweet.provider.FiretweetDataProvider.java
private void showMentionsNotification(AccountPreferences pref, long position) { final long accountId = pref.getAccountId(); final Context context = getContext(); final Resources resources = context.getResources(); final NotificationManager nm = getNotificationManager(); final Expression selection; if (pref.isNotificationFollowingOnly()) { selection = Expression.and(Expression.equals(Statuses.ACCOUNT_ID, accountId), Expression.greaterThan(Statuses.STATUS_ID, position), Expression.equals(Statuses.IS_FOLLOWING, 1)); } else {/*from w w w.ja v a 2 s . c o m*/ selection = Expression.and(Expression.equals(Statuses.ACCOUNT_ID, accountId), Expression.greaterThan(Statuses.STATUS_ID, position)); } final String filteredSelection = Utils.buildStatusFilterWhereClause(Mentions.TABLE_NAME, selection) .getSQL(); final String[] userProjection = { Statuses.USER_ID, Statuses.USER_NAME, Statuses.USER_SCREEN_NAME }; final String[] statusProjection = { Statuses.STATUS_ID, Statuses.USER_ID, Statuses.USER_NAME, Statuses.USER_SCREEN_NAME, Statuses.TEXT_UNESCAPED, Statuses.STATUS_TIMESTAMP }; final Cursor statusCursor = mDatabaseWrapper.query(Mentions.TABLE_NAME, statusProjection, filteredSelection, null, null, null, Statuses.SORT_ORDER_TIMESTAMP_DESC); final Cursor userCursor = mDatabaseWrapper.query(Mentions.TABLE_NAME, userProjection, filteredSelection, null, Statuses.USER_ID, null, Statuses.SORT_ORDER_TIMESTAMP_DESC); try { final int usersCount = userCursor.getCount(); final int statusesCount = statusCursor.getCount(); if (statusesCount == 0 || usersCount == 0) return; final String accountName = Utils.getAccountName(context, accountId); final String accountScreenName = Utils.getAccountScreenName(context, accountId); final int idxStatusText = statusCursor.getColumnIndex(Statuses.TEXT_UNESCAPED), idxStatusId = statusCursor.getColumnIndex(Statuses.STATUS_ID), idxStatusTimestamp = statusCursor.getColumnIndex(Statuses.STATUS_TIMESTAMP), idxStatusUserName = statusCursor.getColumnIndex(Statuses.USER_NAME), idxStatusUserScreenName = statusCursor.getColumnIndex(Statuses.USER_SCREEN_NAME), idxUserName = userCursor.getColumnIndex(Statuses.USER_NAME), idxUserScreenName = userCursor.getColumnIndex(Statuses.USER_NAME), idxUserId = userCursor.getColumnIndex(Statuses.USER_NAME); final CharSequence notificationTitle = resources.getQuantityString(R.plurals.N_new_mentions, statusesCount, statusesCount); final String notificationContent; userCursor.moveToFirst(); final String displayName = UserColorNameUtils.getUserNickname(context, userCursor.getLong(idxUserId), mNameFirst ? userCursor.getString(idxUserName) : userCursor.getString(idxUserScreenName)); if (usersCount == 1) { notificationContent = context.getString(R.string.notification_mention, displayName); } else { notificationContent = context.getString(R.string.notification_mention_multiple, displayName, usersCount - 1); } // Add rich notification and get latest tweet timestamp long when = -1, statusId = -1; final InboxStyle style = new InboxStyle(); for (int i = 0, j = Math.min(statusesCount, 5); statusCursor.moveToPosition(i) && i < j; i++) { if (when == -1) { when = statusCursor.getLong(idxStatusTimestamp); } if (statusId == -1) { statusId = statusCursor.getLong(idxStatusId); } final SpannableStringBuilder sb = new SpannableStringBuilder(); sb.append(UserColorNameUtils.getUserNickname(context, statusCursor.getLong(idxUserId), mNameFirst ? statusCursor.getString(idxStatusUserName) : statusCursor.getString(idxStatusUserScreenName))); sb.setSpan(new StyleSpan(Typeface.BOLD), 0, sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); sb.append(' '); sb.append(statusCursor.getString(idxStatusText)); style.addLine(sb); } if (mNameFirst) { style.setSummaryText(accountName); } else { style.setSummaryText("@" + accountScreenName); } // Setup notification final NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setAutoCancel(true); builder.setSmallIcon(R.drawable.ic_stat_mention); builder.setTicker(notificationTitle); builder.setContentTitle(notificationTitle); builder.setContentText(notificationContent); builder.setCategory(NotificationCompat.CATEGORY_SOCIAL); builder.setContentIntent(getContentIntent(context, AUTHORITY_MENTIONS, accountId)); builder.setDeleteIntent(getDeleteIntent(context, AUTHORITY_MENTIONS, accountId, statusId)); builder.setNumber(statusesCount); builder.setWhen(when); builder.setStyle(style); builder.setColor(pref.getNotificationLightColor()); setNotificationPreferences(builder, pref, pref.getMentionsNotificationType()); nm.notify("mentions_" + accountId, NOTIFICATION_ID_MENTIONS_TIMELINE, builder.build()); Utils.sendPebbleNotification(context, notificationContent); } finally { statusCursor.close(); userCursor.close(); } }
From source file:com.android.messaging.datamodel.BugleNotifications.java
/** * buildBoldedMessage - build a formatted message where the title is bold, there's a * separator, then the message.//www. j ava 2 s .c o m */ private static CharSequence buildBoldedMessage(final String title, final CharSequence message, final Uri attachmentUri, final String attachmentType, final int separatorId) { final Context context = Factory.get().getApplicationContext(); final SpannableStringBuilder spanBuilder = new SpannableStringBuilder(); // Boldify the title (which is the sender's name) if (!TextUtils.isEmpty(title)) { spanBuilder.append(title); spanBuilder.setSpan(new StyleSpan(Typeface.BOLD), 0, title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } if (!TextUtils.isEmpty(message)) { if (spanBuilder.length() > 0) { spanBuilder.append(context.getString(separatorId)); } spanBuilder.append(message); } if (attachmentUri != null) { if (spanBuilder.length() > 0) { final String separator = context.getString(R.string.notification_separator); spanBuilder.append(separator); } spanBuilder.append(formatAttachmentTag(null, attachmentType)); } return spanBuilder; }
From source file:com.concentriclivers.mms.com.android.mms.transaction.MessagingNotification.java
protected static CharSequence buildTickerMessage(Context context, String address, String subject, String body) { String displayAddress = Contact.get(address, true).getName(); StringBuilder buf = new StringBuilder( displayAddress == null ? "" : displayAddress.replace('\n', ' ').replace('\r', ' ')); buf.append(':').append(' '); int offset = buf.length(); if (!TextUtils.isEmpty(subject)) { subject = subject.replace('\n', ' ').replace('\r', ' '); buf.append(subject);/*from w w w .ja v a2 s.c om*/ buf.append(' '); } if (!TextUtils.isEmpty(body)) { body = body.replace('\n', ' ').replace('\r', ' '); buf.append(body); } SpannableString spanText = new SpannableString(buf.toString()); spanText.setSpan(new StyleSpan(Typeface.BOLD), 0, offset, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return spanText; }
From source file:org.getlantern.firetweet.provider.FiretweetDataProvider.java
private void showMessagesNotification(AccountPreferences pref, StringLongPair[] pairs, ContentValues[] valuesArray) {/* w ww .ja va 2s. c o m*/ final long accountId = pref.getAccountId(); final long prevOldestId = mReadStateManager.getPosition(TAG_OLDEST_MESSAGES, String.valueOf(accountId)); long oldestId = -1; for (final ContentValues contentValues : valuesArray) { final long messageId = contentValues.getAsLong(DirectMessages.MESSAGE_ID); oldestId = oldestId < 0 ? messageId : Math.min(oldestId, messageId); if (messageId <= prevOldestId) return; } mReadStateManager.setPosition(TAG_OLDEST_MESSAGES, String.valueOf(accountId), oldestId, false); final Context context = getContext(); final Resources resources = context.getResources(); final NotificationManager nm = getNotificationManager(); final ArrayList<Expression> orExpressions = new ArrayList<>(); final String prefix = accountId + "-"; final int prefixLength = prefix.length(); final Set<Long> senderIds = new CompactHashSet<>(); for (StringLongPair pair : pairs) { final String key = pair.getKey(); if (key.startsWith(prefix)) { final long senderId = Long.parseLong(key.substring(prefixLength)); senderIds.add(senderId); final Expression expression = Expression.and(Expression.equals(DirectMessages.SENDER_ID, senderId), Expression.greaterThan(DirectMessages.MESSAGE_ID, pair.getValue())); orExpressions.add(expression); } } orExpressions .add(Expression.notIn(new Column(DirectMessages.SENDER_ID), new RawItemArray(senderIds.toArray()))); final Expression selection = Expression.and(Expression.equals(DirectMessages.ACCOUNT_ID, accountId), Expression.greaterThan(DirectMessages.MESSAGE_ID, prevOldestId), Expression.or(orExpressions.toArray(new Expression[orExpressions.size()]))); final String filteredSelection = selection.getSQL(); final String[] userProjection = { DirectMessages.SENDER_ID, DirectMessages.SENDER_NAME, DirectMessages.SENDER_SCREEN_NAME }; final String[] messageProjection = { DirectMessages.MESSAGE_ID, DirectMessages.SENDER_ID, DirectMessages.SENDER_NAME, DirectMessages.SENDER_SCREEN_NAME, DirectMessages.TEXT_UNESCAPED, DirectMessages.MESSAGE_TIMESTAMP }; final Cursor messageCursor = mDatabaseWrapper.query(DirectMessages.Inbox.TABLE_NAME, messageProjection, filteredSelection, null, null, null, DirectMessages.DEFAULT_SORT_ORDER); final Cursor userCursor = mDatabaseWrapper.query(DirectMessages.Inbox.TABLE_NAME, userProjection, filteredSelection, null, DirectMessages.SENDER_ID, null, DirectMessages.DEFAULT_SORT_ORDER); try { final int usersCount = userCursor.getCount(); final int messagesCount = messageCursor.getCount(); if (messagesCount == 0 || usersCount == 0) return; final String accountName = Utils.getAccountName(context, accountId); final String accountScreenName = Utils.getAccountScreenName(context, accountId); final int idxMessageText = messageCursor.getColumnIndex(DirectMessages.TEXT_UNESCAPED), idxMessageTimestamp = messageCursor.getColumnIndex(DirectMessages.MESSAGE_TIMESTAMP), idxMessageId = messageCursor.getColumnIndex(DirectMessages.MESSAGE_ID), idxMessageUserId = messageCursor.getColumnIndex(DirectMessages.SENDER_ID), idxMessageUserName = messageCursor.getColumnIndex(DirectMessages.SENDER_NAME), idxMessageUserScreenName = messageCursor.getColumnIndex(DirectMessages.SENDER_SCREEN_NAME), idxUserName = userCursor.getColumnIndex(DirectMessages.SENDER_NAME), idxUserScreenName = userCursor.getColumnIndex(DirectMessages.SENDER_NAME), idxUserId = userCursor.getColumnIndex(DirectMessages.SENDER_NAME); final CharSequence notificationTitle = resources.getQuantityString(R.plurals.N_new_messages, messagesCount, messagesCount); final String notificationContent; userCursor.moveToFirst(); final String displayName = UserColorNameUtils.getUserNickname(context, userCursor.getLong(idxUserId), mNameFirst ? userCursor.getString(idxUserName) : userCursor.getString(idxUserScreenName)); if (usersCount == 1) { if (messagesCount == 1) { notificationContent = context.getString(R.string.notification_direct_message, displayName); } else { notificationContent = context.getString(R.string.notification_direct_message_multiple_messages, displayName, messagesCount); } } else { notificationContent = context.getString(R.string.notification_direct_message_multiple_users, displayName, usersCount - 1, messagesCount); } final LongSparseArray<Long> idsMap = new LongSparseArray<>(); // Add rich notification and get latest tweet timestamp long when = -1; final InboxStyle style = new InboxStyle(); for (int i = 0; messageCursor.moveToPosition(i) && i < messagesCount; i++) { if (when < 0) { when = messageCursor.getLong(idxMessageTimestamp); } if (i < 5) { final SpannableStringBuilder sb = new SpannableStringBuilder(); sb.append(UserColorNameUtils.getUserNickname(context, messageCursor.getLong(idxUserId), mNameFirst ? messageCursor.getString(idxMessageUserName) : messageCursor.getString(idxMessageUserScreenName))); sb.setSpan(new StyleSpan(Typeface.BOLD), 0, sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); sb.append(' '); sb.append(messageCursor.getString(idxMessageText)); style.addLine(sb); } final long userId = messageCursor.getLong(idxMessageUserId); final long messageId = messageCursor.getLong(idxMessageId); idsMap.put(userId, Math.max(idsMap.get(userId, -1L), messageId)); } if (mNameFirst) { style.setSummaryText(accountName); } else { style.setSummaryText("@" + accountScreenName); } final StringLongPair[] positions = new StringLongPair[idsMap.size()]; for (int i = 0, j = idsMap.size(); i < j; i++) { positions[i] = new StringLongPair(String.valueOf(idsMap.keyAt(i)), idsMap.valueAt(i)); } // Setup notification final NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setAutoCancel(true); builder.setSmallIcon(R.drawable.ic_stat_direct_message); builder.setTicker(notificationTitle); builder.setContentTitle(notificationTitle); builder.setContentText(notificationContent); builder.setCategory(NotificationCompat.CATEGORY_SOCIAL); builder.setContentIntent(getContentIntent(context, AUTHORITY_DIRECT_MESSAGES, accountId)); builder.setContentIntent(getDeleteIntent(context, AUTHORITY_DIRECT_MESSAGES, accountId, positions)); builder.setNumber(messagesCount); builder.setWhen(when); builder.setStyle(style); builder.setColor(pref.getNotificationLightColor()); setNotificationPreferences(builder, pref, pref.getDirectMessagesNotificationType()); nm.notify("messages_" + accountId, NOTIFICATION_ID_DIRECT_MESSAGES, builder.build()); Utils.sendPebbleNotification(context, notificationContent); } finally { messageCursor.close(); userCursor.close(); } }
From source file:com.android.mms.transaction.MessagingNotification.java
protected static CharSequence buildTickerMessage(Context context, String address, String subject, String body) { String displayAddress = Contact.get(address, true).getName(); StringBuilder buf = new StringBuilder( displayAddress == null ? "" : displayAddress.replace('\n', ' ').replace('\r', ' ')); if (!TextUtils.isEmpty(subject) && !TextUtils.isEmpty(body)) { buf.append(':').append(' '); }// w w w .j a va 2s . co m int offset = buf.length(); if (!TextUtils.isEmpty(subject)) { subject = subject.replace('\n', ' ').replace('\r', ' '); buf.append(subject); buf.append(' '); } if (!TextUtils.isEmpty(body)) { body = body.replace('\n', ' ').replace('\r', ' '); buf.append(body); } SpannableString spanText = new SpannableString(buf.toString()); spanText.setSpan(new StyleSpan(Typeface.BOLD), 0, offset, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return spanText; }
From source file:ru.valle.btc.MainActivity.java
private void tryToGenerateSpendingTransaction() { final ArrayList<UnspentOutputInfo> unspentOutputs = verifiedUnspentOutputsForTx; final String outputAddress = verifiedRecipientAddressForTx; final long requestedAmountToSend = verifiedAmountToSendForTx; final KeyPair keyPair = verifiedKeyPairForTx; final boolean inputsComesFromJson = verifiedUnspentOutputsComesFromJson; final int predefinedConfirmationsCount = verifiedConfirmationsCount; spendTxDescriptionView.setVisibility(View.GONE); spendTxWarningView.setVisibility(View.GONE); spendTxEdit.setText(""); spendTxEdit.setVisibility(View.GONE); sendTxInBrowserButton.setVisibility(View.GONE); findViewById(R.id.spend_tx_required_age_for_free_tx).setVisibility(View.GONE); // https://blockchain.info/pushtx if (unspentOutputs != null && !unspentOutputs.isEmpty() && !TextUtils.isEmpty(outputAddress) && keyPair != null && requestedAmountToSend >= SEND_MAX && requestedAmountToSend != 0 && !TextUtils.isEmpty(keyPair.address)) { cancelAllRunningTasks();/*from w w w . ja va 2 s . c o m*/ generateTransactionTask = new AsyncTask<Void, Void, GenerateTransactionResult>() { @Override protected GenerateTransactionResult doInBackground(Void... voids) { final Transaction spendTx; try { long availableAmount = 0; for (UnspentOutputInfo unspentOutputInfo : unspentOutputs) { availableAmount += unspentOutputInfo.value; } long amount; if (availableAmount == requestedAmountToSend || requestedAmountToSend == SEND_MAX) { //transfer maximum possible amount amount = -1; } else { amount = requestedAmountToSend; } long extraFee; SharedPreferences preferences = PreferenceManager .getDefaultSharedPreferences(MainActivity.this); try { extraFee = preferences.getLong(PreferencesActivity.PREF_EXTRA_FEE, FeePreference.PREF_EXTRA_FEE_DEFAULT); } catch (ClassCastException e) { preferences.edit().remove(PreferencesActivity.PREF_EXTRA_FEE) .putLong(PreferencesActivity.PREF_EXTRA_FEE, FeePreference.PREF_EXTRA_FEE_DEFAULT) .commit(); extraFee = FeePreference.PREF_EXTRA_FEE_DEFAULT; } spendTx = BTCUtils.createTransaction(unspentOutputs, outputAddress, keyPair.address, amount, extraFee, keyPair.publicKey, keyPair.privateKey); //6. double check that generated transaction is valid Transaction.Script[] relatedScripts = new Transaction.Script[spendTx.inputs.length]; for (int i = 0; i < spendTx.inputs.length; i++) { Transaction.Input input = spendTx.inputs[i]; for (UnspentOutputInfo unspentOutput : unspentOutputs) { if (Arrays.equals(unspentOutput.txHash, input.outPoint.hash) && unspentOutput.outputIndex == input.outPoint.index) { relatedScripts[i] = unspentOutput.script; break; } } } BTCUtils.verify(relatedScripts, spendTx); } catch (BitcoinException e) { switch (e.errorCode) { case BitcoinException.ERR_INSUFFICIENT_FUNDS: return new GenerateTransactionResult(getString(R.string.error_not_enough_funds), GenerateTransactionResult.ERROR_SOURCE_AMOUNT_FIELD); case BitcoinException.ERR_FEE_IS_TOO_BIG: return new GenerateTransactionResult(getString(R.string.generated_tx_have_too_big_fee), GenerateTransactionResult.ERROR_SOURCE_INPUT_TX_FIELD); case BitcoinException.ERR_MEANINGLESS_OPERATION://input, output and change addresses are same. return new GenerateTransactionResult(getString(R.string.output_address_same_as_input), GenerateTransactionResult.ERROR_SOURCE_ADDRESS_FIELD); // case BitcoinException.ERR_INCORRECT_PASSWORD // case BitcoinException.ERR_WRONG_TYPE: // case BitcoinException.ERR_FEE_IS_LESS_THEN_ZERO // case BitcoinException.ERR_CHANGE_IS_LESS_THEN_ZERO // case BitcoinException.ERR_AMOUNT_TO_SEND_IS_LESS_THEN_ZERO default: return new GenerateTransactionResult( getString(R.string.error_failed_to_create_transaction) + ": " + e.getMessage(), GenerateTransactionResult.ERROR_SOURCE_UNKNOWN); } } catch (Exception e) { return new GenerateTransactionResult( getString(R.string.error_failed_to_create_transaction) + ": " + e, GenerateTransactionResult.ERROR_SOURCE_UNKNOWN); } long inValue = 0; for (Transaction.Input input : spendTx.inputs) { for (UnspentOutputInfo unspentOutput : unspentOutputs) { if (Arrays.equals(unspentOutput.txHash, input.outPoint.hash) && unspentOutput.outputIndex == input.outPoint.index) { inValue += unspentOutput.value; } } } long outValue = 0; for (Transaction.Output output : spendTx.outputs) { outValue += output.value; } long fee = inValue - outValue; return new GenerateTransactionResult(spendTx, fee); } @Override protected void onPostExecute(GenerateTransactionResult result) { super.onPostExecute(result); generateTransactionTask = null; if (result != null) { final TextView rawTxToSpendErr = (TextView) findViewById(R.id.err_raw_tx); if (result.tx != null) { String amountStr = null; Transaction.Script out = null; try { out = Transaction.Script.buildOutput(outputAddress); } catch (BitcoinException ignore) { } if (result.tx.outputs[0].script.equals(out)) { amountStr = BTCUtils.formatValue(result.tx.outputs[0].value); } if (amountStr == null) { rawTxToSpendErr.setText(R.string.error_unknown); } else { String descStr; String feeStr = BTCUtils.formatValue(result.fee); String changeStr; if (result.tx.outputs.length == 1) { changeStr = null; descStr = getString(R.string.spend_tx_description, amountStr, keyPair.address, outputAddress, feeStr); } else if (result.tx.outputs.length == 2) { changeStr = BTCUtils.formatValue(result.tx.outputs[1].value); descStr = getString(R.string.spend_tx_with_change_description, amountStr, keyPair.address, outputAddress, feeStr, changeStr); } else { throw new RuntimeException(); } SpannableStringBuilder descBuilder = new SpannableStringBuilder(descStr); int spanBegin = descStr.indexOf(keyPair.address); if (spanBegin >= 0) {//from ForegroundColorSpan addressColorSpan = new ForegroundColorSpan( getColor(MainActivity.this, R.color.dark_orange)); descBuilder.setSpan(addressColorSpan, spanBegin, spanBegin + keyPair.address.length(), SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE); } if (spanBegin >= 0) { spanBegin = descStr.indexOf(keyPair.address, spanBegin + 1); if (spanBegin >= 0) {//change ForegroundColorSpan addressColorSpan = new ForegroundColorSpan( getColor(MainActivity.this, R.color.dark_orange)); descBuilder.setSpan(addressColorSpan, spanBegin, spanBegin + keyPair.address.length(), SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE); } } spanBegin = descStr.indexOf(outputAddress); if (spanBegin >= 0) {//dest ForegroundColorSpan addressColorSpan = new ForegroundColorSpan( getColor(MainActivity.this, R.color.dark_green)); descBuilder.setSpan(addressColorSpan, spanBegin, spanBegin + outputAddress.length(), SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE); } final String nbspBtc = "\u00a0BTC"; spanBegin = descStr.indexOf(amountStr + nbspBtc); if (spanBegin >= 0) { descBuilder.setSpan(new StyleSpan(Typeface.BOLD), spanBegin, spanBegin + amountStr.length() + nbspBtc.length(), SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE); } spanBegin = descStr.indexOf(feeStr + nbspBtc, spanBegin); if (spanBegin >= 0) { descBuilder.setSpan(new StyleSpan(Typeface.BOLD), spanBegin, spanBegin + feeStr.length() + nbspBtc.length(), SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE); } if (changeStr != null) { spanBegin = descStr.indexOf(changeStr + nbspBtc, spanBegin); if (spanBegin >= 0) { descBuilder.setSpan(new StyleSpan(Typeface.BOLD), spanBegin, spanBegin + changeStr.length() + nbspBtc.length(), SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE); } } spendTxDescriptionView.setText(descBuilder); spendTxDescriptionView.setVisibility(View.VISIBLE); spendTxWarningView.setVisibility(View.VISIBLE); spendTxEdit.setText(BTCUtils.toHex(result.tx.getBytes())); spendTxEdit.setVisibility(View.VISIBLE); sendTxInBrowserButton.setVisibility(View.VISIBLE); TextView maxAgeView = (TextView) findViewById( R.id.spend_tx_required_age_for_free_tx); CheckBox maxAgeCheckBox = (CheckBox) findViewById( R.id.spend_tx_required_age_for_free_tx_checkbox); if (!inputsComesFromJson) { if (!showNotEligibleForNoFeeBecauseOfBasicConstrains(maxAgeView, result.tx)) { final int confirmations = (int) (BTCUtils.MIN_PRIORITY_FOR_NO_FEE * result.tx.getBytes().length / unspentOutputs.get(0).value); float daysFloat = confirmations / BTCUtils.EXPECTED_BLOCKS_PER_DAY; String timePeriodStr; if (daysFloat <= 1) { int hours = (int) Math.round(Math.ceil(daysFloat / 24)); timePeriodStr = getResources().getQuantityString(R.plurals.hours, hours, hours); } else { int days = (int) Math.round(Math.ceil(daysFloat)); timePeriodStr = getResources().getQuantityString(R.plurals.days, days, days); } maxAgeCheckBox.setText(getString(R.string.input_tx_is_old_enough, getResources().getQuantityString(R.plurals.confirmations, confirmations, confirmations), timePeriodStr)); maxAgeCheckBox.setVisibility(View.VISIBLE); maxAgeCheckBox.setOnCheckedChangeListener(null); maxAgeCheckBox.setChecked(predefinedConfirmationsCount > 0); maxAgeCheckBox.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { verifiedConfirmationsCount = isChecked ? confirmations : -1; onUnspentOutputsInfoChanged(); } }); } else { maxAgeCheckBox.setVisibility(View.GONE); } } else { showNotEligibleForNoFeeBecauseOfBasicConstrains(maxAgeView, result.tx); } } } else if (result.errorSource == GenerateTransactionResult.ERROR_SOURCE_INPUT_TX_FIELD) { rawTxToSpendErr.setText(result.errorMessage); } else if (result.errorSource == GenerateTransactionResult.ERROR_SOURCE_ADDRESS_FIELD || result.errorSource == GenerateTransactionResult.HINT_FOR_ADDRESS_FIELD) { ((TextView) findViewById(R.id.err_recipient_address)).setText(result.errorMessage); } else if (!TextUtils.isEmpty(result.errorMessage) && result.errorSource == GenerateTransactionResult.ERROR_SOURCE_UNKNOWN) { new AlertDialog.Builder(MainActivity.this).setMessage(result.errorMessage) .setPositiveButton(android.R.string.ok, null).show(); } ((TextView) findViewById(R.id.err_amount)) .setText(result.errorSource == GenerateTransactionResult.ERROR_SOURCE_AMOUNT_FIELD ? result.errorMessage : ""); } } private boolean showNotEligibleForNoFeeBecauseOfBasicConstrains(TextView maxAgeView, Transaction tx) { long minOutput = Long.MAX_VALUE; for (Transaction.Output output : tx.outputs) { minOutput = Math.min(output.value, minOutput); } int txLen = tx.getBytes().length; if (txLen >= BTCUtils.MAX_TX_LEN_FOR_NO_FEE) { maxAgeView.setText( getResources().getQuantityText(R.plurals.tx_size_too_big_to_be_free, txLen)); maxAgeView.setVisibility(View.VISIBLE); return true; } else if (minOutput < BTCUtils.MIN_MIN_OUTPUT_VALUE_FOR_NO_FEE) { maxAgeView .setText(getString(R.string.tx_output_is_too_small, BTCUtils.formatValue(minOutput), BTCUtils.formatValue(BTCUtils.MIN_MIN_OUTPUT_VALUE_FOR_NO_FEE))); maxAgeView.setVisibility(View.VISIBLE); return true; } maxAgeView.setVisibility(View.GONE); return false; } }.execute(); } }