1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.messaging.ui;
17 
18 import android.content.ClipData;
19 import android.content.ClipboardManager;
20 import android.content.Context;
21 import android.util.AttributeSet;
22 import android.widget.EditText;
23 
24 /**
25  * We want the EditText used in Conversations to convert text to plain text on paste.  This
26  * conversion would happen anyway on send, so without this class it could appear to the user
27  * that we would send e.g. bold or italic formatting, but in the sent message it would just be
28  * plain text.
29  */
30 public class PlainTextEditText extends EditText {
31     private static final char OBJECT_UNICODE = '\uFFFC';
32 
PlainTextEditText(final Context context, final AttributeSet attrs)33     public PlainTextEditText(final Context context, final AttributeSet attrs) {
34         super(context, attrs);
35     }
36 
37     // Intercept and modify the paste event. Let everything else through unchanged.
38     @Override
onTextContextMenuItem(final int id)39     public boolean onTextContextMenuItem(final int id) {
40         if (id == android.R.id.paste) {
41             // We can use this to know where the text position was originally before we pasted
42             final int selectionStartPrePaste = getSelectionStart();
43 
44             // Let the EditText's normal paste routine fire, then modify the content after.
45             // This is simpler than re-implementing the paste logic, which we'd have to do
46             // if we want to get the text from the clipboard ourselves and then modify it.
47 
48             final boolean result = super.onTextContextMenuItem(id);
49             CharSequence text = getText();
50             int selectionStart = getSelectionStart();
51             int selectionEnd = getSelectionEnd();
52 
53             // There is an option in the Chrome mobile app to copy image; however, instead of the
54             // image in the form of the uri, Chrome gives us the html source for the image, which
55             // the platform paste code turns into the unicode object character. The below section
56             // of code looks for that edge case and replaces it with the url for the image.
57             final int startIndex = selectionStart - 1;
58             final int pasteStringLength = selectionStart - selectionStartPrePaste;
59             // Only going to handle the case where the pasted object is the image
60             if (pasteStringLength == 1 && text.charAt(startIndex) == OBJECT_UNICODE) {
61                 final ClipboardManager clipboard =
62                         (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
63                 final ClipData clip = clipboard.getPrimaryClip();
64                 if (clip != null) {
65                     ClipData.Item item = clip.getItemAt(0);
66                     StringBuilder sb = new StringBuilder(text);
67                     final String url = item.getText().toString();
68                     sb.replace(selectionStartPrePaste, selectionStart, url);
69                     text = sb.toString();
70                     selectionStart = selectionStartPrePaste + url.length();
71                     selectionEnd = selectionStart;
72                 }
73             }
74 
75             // This removes the formatting due to the conversion to string.
76             setText(text.toString(), BufferType.EDITABLE);
77 
78             // Restore the cursor selection state.
79             setSelection(selectionStart, selectionEnd);
80             return result;
81         } else {
82             return super.onTextContextMenuItem(id);
83         }
84     }
85 }
86