diff options
author | David van Tonder <david.vantonder@gmail.com> | 2013-06-11 04:34:59 -0700 |
---|---|---|
committer | Gerrit Code Review <gerrit@cyanogenmod.org> | 2013-06-11 04:34:59 -0700 |
commit | 3aca6c3137f968f4c4103e15f0fbbe0141dd518e (patch) | |
tree | 4efdc478f7892e28761f9a6b4adb6b099620561a | |
parent | b020a3991446f495dd8eff515fec77c3ffc74eac (diff) | |
parent | f756894579dc5e90bec286228d08da95b23b71ae (diff) | |
download | packages_apps_Mms-3aca6c3137f968f4c4103e15f0fbbe0141dd518e.zip packages_apps_Mms-3aca6c3137f968f4c4103e15f0fbbe0141dd518e.tar.gz packages_apps_Mms-3aca6c3137f968f4c4103e15f0fbbe0141dd518e.tar.bz2 |
Merge "Mms: Delay unicode stripping from a message" into cm-10.1
-rw-r--r-- | src/com/android/mms/quickmessage/QmTextWatcher.java | 10 | ||||
-rw-r--r-- | src/com/android/mms/quickmessage/QuickMessagePopup.java | 140 | ||||
-rw-r--r-- | src/com/android/mms/ui/ComposeMessageActivity.java | 141 | ||||
-rw-r--r-- | src/com/android/mms/util/UnicodeFilter.java | 127 |
4 files changed, 168 insertions, 250 deletions
diff --git a/src/com/android/mms/quickmessage/QmTextWatcher.java b/src/com/android/mms/quickmessage/QmTextWatcher.java index c56b0bf..fbc9b3e 100644 --- a/src/com/android/mms/quickmessage/QmTextWatcher.java +++ b/src/com/android/mms/quickmessage/QmTextWatcher.java @@ -25,21 +25,25 @@ import android.view.View; import android.widget.ImageButton; import android.widget.TextView; +import com.android.mms.util.UnicodeFilter; + public class QmTextWatcher implements TextWatcher { private TextView mTextView; private ImageButton mSendButton; private ImageButton mTemplateButton; private int mTemplateCount; + private UnicodeFilter mUnicodeFilter; private Context mContext; private static final int CHARS_REMAINING_BEFORE_COUNTER_SHOWN = 30; public QmTextWatcher(Context context, TextView updateTextView, ImageButton sendButton, - ImageButton templateButton, int templateCount) { + ImageButton templateButton, int templateCount, UnicodeFilter unicodeFilter) { mContext = context; mTextView = updateTextView; mSendButton = sendButton; mTemplateButton = templateButton; mTemplateCount = templateCount; + mUnicodeFilter = unicodeFilter; } public QmTextWatcher(Context context, TextView updateTextView) { @@ -58,6 +62,10 @@ public class QmTextWatcher implements TextWatcher { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { + // strip unicode for message length counting + if (mUnicodeFilter != null) { + s = mUnicodeFilter.filter(s); + } getQuickReplyCounterText(s, mTextView, mSendButton, mTemplateButton, mTemplateCount); // For performance, we will only poke the wakelock on the 1st and every 20th keystroke diff --git a/src/com/android/mms/quickmessage/QuickMessagePopup.java b/src/com/android/mms/quickmessage/QuickMessagePopup.java index efe961c..8754360 100644 --- a/src/com/android/mms/quickmessage/QuickMessagePopup.java +++ b/src/com/android/mms/quickmessage/QuickMessagePopup.java @@ -89,6 +89,7 @@ import com.android.mms.ui.MessageUtils; import com.android.mms.ui.MessagingPreferenceActivity; import com.android.mms.util.EmojiParser; import com.android.mms.util.SmileyParser; +import com.android.mms.util.UnicodeFilter; import com.google.android.mms.MmsException; import java.nio.charset.Charset; @@ -153,6 +154,7 @@ public class QuickMessagePopup extends Activity implements private boolean mDarkTheme = false; private boolean mFullTimestamp = false; private int mUnicodeStripping = MessagingPreferenceActivity.UNICODE_STRIPPING_LEAVE_INTACT; + private UnicodeFilter mUnicodeFilter = null; private boolean mEnableEmojis = false; private int mInputMethod; @@ -938,122 +940,6 @@ public class QuickMessagePopup extends Activity implements //========================================================== /** - * Class copied from ComposeMessageActivity.java - * InputFilter which attempts to substitute characters that cannot be - * encoded in the limited GSM 03.38 character set. In many cases this will - * prevent the keyboards auto-correction feature from inserting characters - * that would switch the message from 7-bit GSM encoding (160 char limit) - * to 16-bit Unicode encoding (70 char limit). - */ - private static class StripUnicode implements InputFilter { - - private CharsetEncoder gsm = - Charset.forName("gsm-03.38-2000").newEncoder(); - - private Pattern diacritics = - Pattern.compile("\\p{InCombiningDiacriticalMarks}"); - - private boolean mStripNonDecodableOnly = false; - - StripUnicode(boolean stripping) { - mStripNonDecodableOnly = stripping; - } - - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - - Boolean unfiltered = true; - StringBuilder output = new StringBuilder(end - start); - - for (int i = start; i < end; i++) { - char c = source.charAt(i); - - // Character is encodable by GSM, skip filtering - if (mStripNonDecodableOnly && gsm.canEncode(c)) { - output.append(c); - } - // Character requires Unicode, try to replace it - else { - unfiltered = false; - String s = String.valueOf(c); - - // Try normalizing the character into Unicode NFKD form and - // stripping out diacritic mark characters. - s = Normalizer.normalize(s, Normalizer.Form.NFKD); - s = diacritics.matcher(s).replaceAll(""); - - // Special case characters that don't get stripped by the - // above technique. - s = s.replace("Œ", "OE"); - s = s.replace("œ", "oe"); - s = s.replace("Ł", "L"); - s = s.replace("ł", "l"); - s = s.replace("Đ", "DJ"); - s = s.replace("đ", "dj"); - s = s.replace("Α", "A"); - s = s.replace("Β", "B"); - s = s.replace("Ε", "E"); - s = s.replace("Ζ", "Z"); - s = s.replace("Η", "H"); - s = s.replace("Ι", "I"); - s = s.replace("Κ", "K"); - s = s.replace("Μ", "M"); - s = s.replace("Ν", "N"); - s = s.replace("Ο", "O"); - s = s.replace("Ρ", "P"); - s = s.replace("Τ", "T"); - s = s.replace("Υ", "Y"); - s = s.replace("Χ", "X"); - s = s.replace("α", "A"); - s = s.replace("β", "B"); - s = s.replace("γ", "Γ"); - s = s.replace("δ", "Δ"); - s = s.replace("ε", "E"); - s = s.replace("ζ", "Z"); - s = s.replace("η", "H"); - s = s.replace("θ", "Θ"); - s = s.replace("ι", "I"); - s = s.replace("κ", "K"); - s = s.replace("λ", "Λ"); - s = s.replace("μ", "M"); - s = s.replace("ν", "N"); - s = s.replace("ξ", "Ξ"); - s = s.replace("ο", "O"); - s = s.replace("π", "Π"); - s = s.replace("ρ", "P"); - s = s.replace("σ", "Σ"); - s = s.replace("τ", "T"); - s = s.replace("υ", "Y"); - s = s.replace("φ", "Φ"); - s = s.replace("χ", "X"); - s = s.replace("ψ", "Ψ"); - s = s.replace("ω", "Ω"); - s = s.replace("ς", "Σ"); - - output.append(s); - } - } - - // No changes were attempted, so don't return anything - if (unfiltered) { - return null; - } - // Source is a spanned string, so copy the spans from it - else if (source instanceof Spanned) { - SpannableString spannedoutput = new SpannableString(output); - TextUtils.copySpansFrom( - (Spanned) source, start, end, null, spannedoutput, 0); - - return spannedoutput; - } - // Source is a vanilla charsequence, so return output as-is - else { - return output; - } - } - } - - /** * Message Pager class, used to display and navigate through the ViewPager pages */ private class MessagePagerAdapter extends PagerAdapter @@ -1114,8 +1000,15 @@ public class QuickMessagePopup extends Activity implements | InputType.TYPE_TEXT_FLAG_MULTI_LINE); qmReplyText.setText(qm.getReplyText()); qmReplyText.setSelection(qm.getReplyText().length()); + + if (mUnicodeStripping != MessagingPreferenceActivity.UNICODE_STRIPPING_LEAVE_INTACT) { + boolean stripNonDecodableOnly = + mUnicodeStripping == MessagingPreferenceActivity.UNICODE_STRIPPING_NON_DECODABLE; + mUnicodeFilter = new UnicodeFilter(stripNonDecodableOnly); + } + qmReplyText.addTextChangedListener(new QmTextWatcher(mContext, qmTextCounter, qmSendButton, - qmTemplatesButton, mNumTemplates)); + qmTemplatesButton, mNumTemplates, mUnicodeFilter)); qmReplyText.setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { @@ -1147,15 +1040,7 @@ public class QuickMessagePopup extends Activity implements }); LengthFilter lengthFilter = new LengthFilter(MmsConfig.getMaxTextLimit()); - - if (mUnicodeStripping != MessagingPreferenceActivity.UNICODE_STRIPPING_LEAVE_INTACT) { - boolean stripNonDecodableOnly = mUnicodeStripping == MessagingPreferenceActivity - .UNICODE_STRIPPING_NON_DECODABLE; - qmReplyText.setFilters(new InputFilter[] { new StripUnicode(stripNonDecodableOnly), - lengthFilter }); - } else { - qmReplyText.setFilters(new InputFilter[] { lengthFilter }); - } + qmReplyText.setFilters(new InputFilter[] { lengthFilter }); QmTextWatcher.getQuickReplyCounterText(qmReplyText.getText().toString(), qmTextCounter, qmSendButton, qmTemplatesButton, mNumTemplates); @@ -1203,6 +1088,9 @@ public class QuickMessagePopup extends Activity implements * @param qm - qm we are replying to (for sender details) */ private void sendMessageAndMoveOn(String message, QuickMessage qm) { + if (mUnicodeFilter != null) { + message = mUnicodeFilter.filter(message).toString(); + } sendQuickMessage(message, qm); // Close the current QM and move on int numMessages = mMessageList.size(); diff --git a/src/com/android/mms/ui/ComposeMessageActivity.java b/src/com/android/mms/ui/ComposeMessageActivity.java index 9758ee7..901c227 100644 --- a/src/com/android/mms/ui/ComposeMessageActivity.java +++ b/src/com/android/mms/ui/ComposeMessageActivity.java @@ -157,6 +157,7 @@ import com.android.mms.util.EmojiParser; import com.android.mms.util.PhoneNumberFormatter; import com.android.mms.util.SendingProgressTokenManager; import com.android.mms.util.SmileyParser; +import com.android.mms.util.UnicodeFilter; import com.android.mms.widget.MmsWidgetProvider; import com.google.android.mms.ContentType; import com.google.android.mms.MmsException; @@ -394,6 +395,8 @@ public class ComposeMessageActivity extends Activity // we should not load the draft. private boolean mShouldLoadDraft; + private UnicodeFilter mUnicodeFilter = null; + private Handler mHandler = new Handler(); // keys for extras and icicles @@ -411,123 +414,6 @@ public class ComposeMessageActivity extends Activity Log.d(TAG, logMsg); } - //========================================================== - // Inner classes - //========================================================== - - // InputFilter which attempts to substitute characters that cannot be - // encoded in the limited GSM 03.38 character set. In many cases this will - // prevent the keyboards auto-correction feature from inserting characters - // that would switch the message from 7-bit GSM encoding (160 char limit) - // to 16-bit Unicode encoding (70 char limit). - - private static class StripUnicode implements InputFilter { - private CharsetEncoder gsm = - Charset.forName("gsm-03.38-2000").newEncoder(); - - private Pattern diacritics = - Pattern.compile("\\p{InCombiningDiacriticalMarks}"); - - private boolean mStripNonDecodableOnly = false; - - StripUnicode(boolean stripping) { - mStripNonDecodableOnly = stripping; - } - - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - - Boolean unfiltered = true; - StringBuilder output = new StringBuilder(end - start); - - for (int i = start; i < end; i++) { - char c = source.charAt(i); - - // Character is encodable by GSM, skip filtering - if (mStripNonDecodableOnly && gsm.canEncode(c)) { - output.append(c); - } - // Character requires Unicode, try to replace it - else { - unfiltered = false; - String s = String.valueOf(c); - - // Try normalizing the character into Unicode NFKD form and - // stripping out diacritic mark characters. - s = Normalizer.normalize(s, Normalizer.Form.NFKD); - s = diacritics.matcher(s).replaceAll(""); - - // Special case characters that don't get stripped by the - // above technique. - s = s.replace("Œ", "OE"); - s = s.replace("œ", "oe"); - s = s.replace("Ł", "L"); - s = s.replace("ł", "l"); - s = s.replace("Đ", "DJ"); - s = s.replace("đ", "dj"); - s = s.replace("Α", "A"); - s = s.replace("Β", "B"); - s = s.replace("Ε", "E"); - s = s.replace("Ζ", "Z"); - s = s.replace("Η", "H"); - s = s.replace("Ι", "I"); - s = s.replace("Κ", "K"); - s = s.replace("Μ", "M"); - s = s.replace("Ν", "N"); - s = s.replace("Ο", "O"); - s = s.replace("Ρ", "P"); - s = s.replace("Τ", "T"); - s = s.replace("Υ", "Y"); - s = s.replace("Χ", "X"); - s = s.replace("α", "A"); - s = s.replace("β", "B"); - s = s.replace("γ", "Γ"); - s = s.replace("δ", "Δ"); - s = s.replace("ε", "E"); - s = s.replace("ζ", "Z"); - s = s.replace("η", "H"); - s = s.replace("θ", "Θ"); - s = s.replace("ι", "I"); - s = s.replace("κ", "K"); - s = s.replace("λ", "Λ"); - s = s.replace("μ", "M"); - s = s.replace("ν", "N"); - s = s.replace("ξ", "Ξ"); - s = s.replace("ο", "O"); - s = s.replace("π", "Π"); - s = s.replace("ρ", "P"); - s = s.replace("σ", "Σ"); - s = s.replace("τ", "T"); - s = s.replace("υ", "Y"); - s = s.replace("φ", "Φ"); - s = s.replace("χ", "X"); - s = s.replace("ψ", "Ψ"); - s = s.replace("ω", "Ω"); - s = s.replace("ς", "Σ"); - - output.append(s); - } - } - - // No changes were attempted, so don't return anything - if (unfiltered) { - return null; - } - // Source is a spanned string, so copy the spans from it - else if (source instanceof Spanned) { - SpannableString spannedoutput = new SpannableString(output); - TextUtils.copySpansFrom( - (Spanned) source, start, end, null, spannedoutput, 0); - - return spannedoutput; - } - // Source is a vanilla charsequence, so return output as-is - else { - return output; - } - } - } - private void editSlideshow() { // The user wants to edit the slideshow. That requires us to persist the slideshow to // disk as a PDU in saveAsMms. This code below does that persisting in a background @@ -2084,14 +1970,12 @@ public class ComposeMessageActivity extends Activity initResourceRefs(); LengthFilter lengthFilter = new LengthFilter(MmsConfig.getMaxTextLimit()); + mTextEditor.setFilters(new InputFilter[] { lengthFilter }); if (unicodeStripping != MessagingPreferenceActivity.UNICODE_STRIPPING_LEAVE_INTACT) { - boolean stripNonDecodableOnly = unicodeStripping == MessagingPreferenceActivity - .UNICODE_STRIPPING_NON_DECODABLE; - mTextEditor.setFilters(new InputFilter[] { new StripUnicode(stripNonDecodableOnly), - lengthFilter }); - } else { - mTextEditor.setFilters(new InputFilter[] { lengthFilter }); + boolean stripNonDecodableOnly = + unicodeStripping == MessagingPreferenceActivity.UNICODE_STRIPPING_NON_DECODABLE; + mUnicodeFilter = new UnicodeFilter(stripNonDecodableOnly); } mContentResolver = getContentResolver(); @@ -3713,6 +3597,8 @@ public class ComposeMessageActivity extends Activity updateSendButtonState(); + // strip unicode for counting characters + s = stripUnicodeIfRequested(s); updateCounter(s, start, before, count); ensureCorrectButtonHeight(); @@ -4020,6 +3906,8 @@ public class ComposeMessageActivity extends Activity // them back once the recipient list has settled. removeRecipientsListeners(); + // strip unicode chars before sending (if applicable) + mWorkingMessage.setText(stripUnicodeIfRequested(mWorkingMessage.getText())); mWorkingMessage.send(mDebugRecipients); mSentMessage = true; @@ -4909,6 +4797,13 @@ public class ComposeMessageActivity extends Activity getLoaderManager().restartLoader(LOAD_TEMPLATES, null, this); } + private CharSequence stripUnicodeIfRequested(CharSequence text) { + if (mUnicodeFilter != null) { + text = mUnicodeFilter.filter(text); + } + return text; + } + @Override public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { ArrayList<Prediction> predictions = mLibrary.recognize(gesture); diff --git a/src/com/android/mms/util/UnicodeFilter.java b/src/com/android/mms/util/UnicodeFilter.java new file mode 100644 index 0000000..d29da73 --- /dev/null +++ b/src/com/android/mms/util/UnicodeFilter.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012-2013 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mms.util; + +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.text.Normalizer; +import java.util.regex.Pattern; + +/** + * Attempts to substitute characters that cannot be encoded in the limited + * GSM 03.38 character set. In many cases this will prevent sending a message + * containing characters that would switch the message from 7-bit GSM + * encoding (160 char limit) to 16-bit Unicode encoding (70 char limit). + */ +public class UnicodeFilter { + private CharsetEncoder gsm = + Charset.forName("gsm-03.38-2000").newEncoder(); + + private Pattern diacritics = + Pattern.compile("\\p{InCombiningDiacriticalMarks}"); + + private boolean mStripNonDecodableOnly; + + public UnicodeFilter(boolean stripNonDecodableOnly) { + mStripNonDecodableOnly = stripNonDecodableOnly; + } + + public CharSequence filter(CharSequence source) { + StringBuilder output = new StringBuilder(source); + final int sourceLength = source.length(); + + for (int i = 0; i < sourceLength; i++) { + char c = source.charAt(i); + + // Character requires Unicode, try to replace it + if (!mStripNonDecodableOnly || !gsm.canEncode(c)) { + String s = String.valueOf(c); + + // Try normalizing the character into Unicode NFKD form and + // stripping out diacritic mark characters. + s = Normalizer.normalize(s, Normalizer.Form.NFKD); + s = diacritics.matcher(s).replaceAll(""); + + // Special case characters that don't get stripped by the + // above technique. + s = s.replace("Œ", "OE"); + s = s.replace("œ", "oe"); + s = s.replace("Ł", "L"); + s = s.replace("ł", "l"); + s = s.replace("Đ", "DJ"); + s = s.replace("đ", "dj"); + s = s.replace("Α", "A"); + s = s.replace("Β", "B"); + s = s.replace("Ε", "E"); + s = s.replace("Ζ", "Z"); + s = s.replace("Η", "H"); + s = s.replace("Ι", "I"); + s = s.replace("Κ", "K"); + s = s.replace("Μ", "M"); + s = s.replace("Ν", "N"); + s = s.replace("Ο", "O"); + s = s.replace("Ρ", "P"); + s = s.replace("Τ", "T"); + s = s.replace("Υ", "Y"); + s = s.replace("Χ", "X"); + s = s.replace("α", "A"); + s = s.replace("β", "B"); + s = s.replace("γ", "Γ"); + s = s.replace("δ", "Δ"); + s = s.replace("ε", "E"); + s = s.replace("ζ", "Z"); + s = s.replace("η", "H"); + s = s.replace("θ", "Θ"); + s = s.replace("ι", "I"); + s = s.replace("κ", "K"); + s = s.replace("λ", "Λ"); + s = s.replace("μ", "M"); + s = s.replace("ν", "N"); + s = s.replace("ξ", "Ξ"); + s = s.replace("ο", "O"); + s = s.replace("π", "Π"); + s = s.replace("ρ", "P"); + s = s.replace("σ", "Σ"); + s = s.replace("τ", "T"); + s = s.replace("υ", "Y"); + s = s.replace("φ", "Φ"); + s = s.replace("χ", "X"); + s = s.replace("ψ", "Ψ"); + s = s.replace("ω", "Ω"); + s = s.replace("ς", "Σ"); + + output.replace(i, i + 1, s); + } + } + + // Source is a spanned string, so copy the spans from it + if (source instanceof Spanned) { + SpannableString spannedoutput = new SpannableString(output); + TextUtils.copySpansFrom( + (Spanned) source, 0, sourceLength, null, spannedoutput, 0); + + return spannedoutput; + } + + // Source is a vanilla charsequence, so return output as-is + return output.toString(); + } +} |