From d5f17a870bd131c4c1a8e4731671a6980b6bcbf6 Mon Sep 17 00:00:00 2001 From: mindyp Date: Sat, 29 Sep 2012 12:39:15 -0700 Subject: Fix crashes associated with new logic to replace entire address with name + address Fixes b/7257614 crash when replying to a message Change-Id: I6dcda376073f941fba4b09a647bdb00a92e4ccce --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index fde4b6e..615e886 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -2334,8 +2334,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements mHandler.post(new Runnable() { @Override public void run() { - SpannableStringBuilder text = new SpannableStringBuilder(getText() - .toString()); Editable oldText = getText(); int start, end; int i = 0; @@ -2351,13 +2349,12 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements createAddressText(replacement.getEntry()).trim()); displayText.setSpan(replacement, 0, displayText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - text.replace(start, end, displayText); + oldText.replace(start, end, displayText); replacement.setOriginalText(displayText.toString()); } i++; } originalRecipients.clear(); - setText(text); } }); } -- cgit v1.2.3 From afca3691912c1986f4ef2dae3c2187340c1c19c1 Mon Sep 17 00:00:00 2001 From: mindyp Date: Mon, 1 Oct 2012 08:22:42 -0700 Subject: Add comments to the recipientedittextview replace code. makes it easier for others to debug/ review Change-Id: Icdcbaa9074c81ef33943b24e8e0b544513360d8a --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 615e886..eac398a 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -2338,6 +2338,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements int start, end; int i = 0; for (RecipientChip chip : originalRecipients) { + // Find the location of the chip in the text currently shown. start = oldText.getSpanStart(chip); if (start != -1) { end = oldText.getSpanEnd(chip); @@ -2349,6 +2350,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements createAddressText(replacement.getEntry()).trim()); displayText.setSpan(replacement, 0, displayText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + // Replace the old text we found with with the new display text, + // which now may also contain the display name of the recipient. oldText.replace(start, end, displayText); replacement.setOriginalText(displayText.toString()); } -- cgit v1.2.3 From 17c922958f2a9bad8b22675e7daf9b40bf6ef2ce Mon Sep 17 00:00:00 2001 From: mindyp Date: Wed, 3 Oct 2012 11:57:42 -0700 Subject: Make sure we check the most up to date text for the token offsets. The issue here was that we were using the old version of the editable string (cached in var text) to look for the start/end of tokens, but the result of calling commitChip may have updated the text (added corrective rfc822 formatting, or a display name) Fixes b/7268603 [Manta] List of email addresses pasted into the To field is broken Change-Id: Iccc8dbf78a018c84fd818582d10ff2b02a787276 --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index eac398a..dc73933 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -2023,8 +2023,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } else { if (!TextUtils.isEmpty(chipText)) { // There may be a space to replace with this chip's new - // associated - // space. Check for it + // associated space. Check for it int toReplace = end; while (toReplace >= 0 && toReplace < editable.length() && editable.charAt(toReplace) == ' ') { @@ -2236,7 +2235,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements int tokenEnd; RecipientChip createdChip; while (tokenStart < originalTokenStart) { - tokenEnd = movePastTerminators(mTokenizer.findTokenEnd(text, tokenStart)); + tokenEnd = movePastTerminators(mTokenizer.findTokenEnd(getText().toString(), + tokenStart)); commitChip(tokenStart, tokenEnd, getText()); createdChip = findChip(tokenStart); if (createdChip == null) { @@ -2388,8 +2388,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (RecipientEntry.isCreatedRecipient(temp.getEntry().getContactId()) && getSpannable().getSpanStart(temp) != -1) { // Replace this. - final RecipientEntry entry = createValidatedEntry(entries - .get(tokenizeAddress(temp.getEntry().getDestination()).toLowerCase())); + final RecipientEntry entry = createValidatedEntry(entries.get(tokenizeAddress( + temp.getEntry().getDestination()).toLowerCase())); if (entry != null) { mHandler.post(new Runnable() { @Override -- cgit v1.2.3 From 917f53e9762be3c8b2eafa58cf6ab825d2cc9c9e Mon Sep 17 00:00:00 2001 From: Paul Westbrook Date: Fri, 12 Oct 2012 11:42:57 -0700 Subject: Set the scale type for the default image icon By setting the scale type to center, the default icon is not scaled up. Bug: 7298245 Bug: 7340457 Change-Id: I66200a1c751ca80e878e55a7b9daa656a6cbe98d --- photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java index 429c403..8e47737 100644 --- a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java +++ b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java @@ -286,6 +286,7 @@ public class PhotoViewFragment extends Fragment implements // no preview, show default mPhotoPreviewImage.setVisibility(View.VISIBLE); mPhotoPreviewImage.setImageResource(R.drawable.default_image); + mPhotoPreviewImage.setScaleType(ImageView.ScaleType.CENTER); mProgressBarNeeded = false; } else { -- cgit v1.2.3 From 28c2b3bde4084af90a4951b27f5570a7fe7c5fa9 Mon Sep 17 00:00:00 2001 From: Paul Westbrook Date: Fri, 12 Oct 2012 17:05:23 -0700 Subject: Load preview first If the preview is available, load the it first, while waiting for the full size image to load Bug: 7340082 Bug: 7298245 Change-Id: I64934001d832844a776f8d9c1f2abcece552f79c --- .../ex/photo/fragments/PhotoViewFragment.java | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java index 8e47737..2e99bd8 100644 --- a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java +++ b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java @@ -209,7 +209,7 @@ public class PhotoViewFragment extends Fragment implements mCallback.addScreenListener(this); mCallback.addCursorListener(this); - getLoaderManager().initLoader(LOADER_ID_PHOTO, null, this); + getLoaderManager().initLoader(LOADER_ID_THUMBNAIL, null, this); super.onResume(); } @@ -269,10 +269,6 @@ public class PhotoViewFragment extends Fragment implements bindPhoto(data); mPhotoPreviewAndProgress.setVisibility(View.GONE); mProgressBarNeeded = false; - } else { - // Received a null result for the full size image. Instead attempt to load the - // thumbnail - getLoaderManager().initLoader(LOADER_ID_THUMBNAIL, null, this); } break; case LOADER_ID_THUMBNAIL: @@ -282,18 +278,20 @@ public class PhotoViewFragment extends Fragment implements mPhotoPreviewAndProgress.setVisibility(View.GONE); mProgressBarNeeded = false; return; - } else if (data == null) { - // no preview, show default - mPhotoPreviewImage.setVisibility(View.VISIBLE); - mPhotoPreviewImage.setImageResource(R.drawable.default_image); - mPhotoPreviewImage.setScaleType(ImageView.ScaleType.CENTER); - - mProgressBarNeeded = false; } else { + // Make the preview image view visible mPhotoPreviewImage.setVisibility(View.VISIBLE); - mPhotoPreviewImage.setImageBitmap(data); - mProgressBarNeeded = false; + if (data == null) { + // no preview, show default + mPhotoPreviewImage.setImageResource(R.drawable.default_image); + mPhotoPreviewImage.setScaleType(ImageView.ScaleType.CENTER); + } else { + // Show the preview + mPhotoPreviewImage.setImageBitmap(data); + } + // Now load the full size image + getLoaderManager().initLoader(LOADER_ID_PHOTO, null, this); } break; default: -- cgit v1.2.3 From b1b8fc2577d8ce9493608056cef6a725437a5ef2 Mon Sep 17 00:00:00 2001 From: Paul Westbrook Date: Wed, 24 Oct 2012 08:22:18 -0700 Subject: Restart loader on attachment cursor updates Bug: 7403076 Change-Id: I620403db9f7304e99ca4e9c0c58a439e277225d0 --- .../src/com/android/ex/photo/fragments/PhotoViewFragment.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java index 2e99bd8..2ecbeb7 100644 --- a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java +++ b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java @@ -272,7 +272,7 @@ public class PhotoViewFragment extends Fragment implements } break; case LOADER_ID_THUMBNAIL: - if (isPhotoBound()) { + if (isPhotoBound()) { // There is need to do anything with the thumbnail image, as the full size // image is being shown. mPhotoPreviewAndProgress.setVisibility(View.GONE); @@ -346,6 +346,10 @@ public class PhotoViewFragment extends Fragment implements // we're not in the foreground; reset our view resetViews(); } else { + if (!isPhotoBound()) { + // Restart the loader + getLoaderManager().restartLoader(LOADER_ID_THUMBNAIL, null, this); + } mCallback.onFragmentVisible(this); } } -- cgit v1.2.3 From 48a26c9dcf012645315a0b77c687f57476d452a0 Mon Sep 17 00:00:00 2001 From: Paul Westbrook Date: Thu, 25 Oct 2012 10:27:38 -0700 Subject: Show old results Keep showing old recipient results when no local results are returned, if we are waiting for server results Bug: 7407129 Change-Id: If495ff6437da064206923dc95ee61b7a4f19c2f3 --- .../com/android/ex/chips/BaseRecipientAdapter.java | 41 +++++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/chips/src/com/android/ex/chips/BaseRecipientAdapter.java b/chips/src/com/android/ex/chips/BaseRecipientAdapter.java index 2e1491a..c0cfa19 100644 --- a/chips/src/com/android/ex/chips/BaseRecipientAdapter.java +++ b/chips/src/com/android/ex/chips/BaseRecipientAdapter.java @@ -204,6 +204,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter Cursor directoryCursor = null; if (TextUtils.isEmpty(constraint)) { + clearTempEntries(); // Return empty results. return results; } @@ -278,12 +279,21 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter // TODO: Fix it. mCurrentConstraint = constraint; + clearTempEntries(); + if (results.values != null) { DefaultFilterResult defaultFilterResult = (DefaultFilterResult) results.values; mEntryMap = defaultFilterResult.entryMap; mNonAggregatedEntries = defaultFilterResult.nonAggregatedEntries; mExistingDestinations = defaultFilterResult.existingDestinations; + // If there are no local results, in the new result set, cache off what had been + // shown to the user for use until the first directory result is returned + if (defaultFilterResult.entries.size() == 0 && + defaultFilterResult.paramsList != null) { + cacheCurrentEntries(); + } + updateEntries(defaultFilterResult.entries); // We need to search other remote directories, doing other Filter requests. @@ -404,6 +414,13 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter } mDelayedMessageHandler.sendDelayedLoadMessage(); } + + // If this directory result has some items, or there are no more directories that + // we are waiting for, clear the temp results + if (results.count > 0 || mRemainingDirectoryCount == 0) { + // Clear the temp entries + clearTempEntries(); + } } // Show the list again without "waiting" message. @@ -442,6 +459,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter private Set mExistingDestinations; /** Note: use {@link #updateEntries(List)} to update this variable. */ private List mEntries; + private List mTempEntries; /** The number of directories this adapter is waiting for results. */ private int mRemainingDirectoryCount; @@ -694,6 +712,18 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter notifyDataSetChanged(); } + private void cacheCurrentEntries() { + mTempEntries = mEntries; + } + + private void clearTempEntries() { + mTempEntries = null; + } + + private List getEntries() { + return mTempEntries != null ? mTempEntries : mEntries; + } + private void tryFetchPhoto(final RecipientEntry entry) { final Uri photoThumbnailUri = entry.getPhotoThumbnailUri(); if (photoThumbnailUri != null) { @@ -799,12 +829,13 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter @Override public int getCount() { - return mEntries != null ? mEntries.size() : 0; + final List entries = getEntries(); + return entries != null ? entries.size() : 0; } @Override public Object getItem(int position) { - return mEntries.get(position); + return getEntries().get(position); } @Override @@ -819,17 +850,17 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter @Override public int getItemViewType(int position) { - return mEntries.get(position).getEntryType(); + return getEntries().get(position).getEntryType(); } @Override public boolean isEnabled(int position) { - return mEntries.get(position).isSelectable(); + return getEntries().get(position).isSelectable(); } @Override public View getView(int position, View convertView, ViewGroup parent) { - final RecipientEntry entry = mEntries.get(position); + final RecipientEntry entry = getEntries().get(position); String displayName = entry.getDisplayName(); String destination = entry.getDestination(); if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, destination)) { -- cgit v1.2.3 From a1bdcf1af2c39a0d8b0d0fb8f32ea43a70aed17f Mon Sep 17 00:00:00 2001 From: Mark Wei Date: Thu, 25 Oct 2012 14:12:23 -0700 Subject: Fix for panorama icon not always showing up in photo viewer. Bug: 7392422 Change-Id: Ifff054c86366eb0b495a06ead9e0dc60123e90c4 --- photoviewer/src/com/android/ex/photo/PhotoViewActivity.java | 3 +++ photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java b/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java index 5231ca1..2a24e1f 100644 --- a/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java +++ b/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java @@ -532,4 +532,7 @@ public class PhotoViewActivity extends Activity implements postActionBarHideRunnableWithDelay(); } } + + public void onNewPhotoLoaded() { + } } diff --git a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java index 2ecbeb7..efb8145 100644 --- a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java +++ b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java @@ -302,8 +302,10 @@ public class PhotoViewFragment extends Fragment implements // Hide the progress bar as it isn't needed anymore. mPhotoProgressBar.setVisibility(View.GONE); } + if (data != null) { + mCallback.onNewPhotoLoaded(); + } - mCallback.setViewActivated(); setViewVisibility(); } -- cgit v1.2.3 From c270a161307eeeee3aac5f5ef91424fbe25ce1e9 Mon Sep 17 00:00:00 2001 From: mindyp Date: Tue, 6 Nov 2012 10:54:05 -0800 Subject: Reset maxlines when the user expands text To avoid an initial jump when changing over a possibly large numbers of contacts to chips, start with maxlines of 2 from some apps, and eliminate this when the user chooses to expand. Part of b/7481045 recipient address briefly drawn w/o friendly name Change-Id: I5c8cd5c1569befa28a67ddb1f4153e03e896c25a --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index dc73933..9aea16d 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -441,6 +441,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } private void expand() { + if (mShouldShrink) { + setMaxLines(Integer.MAX_VALUE); + } removeMoreChip(); setCursorVisible(true); Editable text = getText(); @@ -2388,8 +2391,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (RecipientEntry.isCreatedRecipient(temp.getEntry().getContactId()) && getSpannable().getSpanStart(temp) != -1) { // Replace this. - final RecipientEntry entry = createValidatedEntry(entries.get(tokenizeAddress( - temp.getEntry().getDestination()).toLowerCase())); + final RecipientEntry entry = createValidatedEntry(entries.get( + tokenizeAddress(temp.getEntry().getDestination()).toLowerCase())); if (entry != null) { mHandler.post(new Runnable() { @Override -- cgit v1.2.3 From d5f7739013e4e4e392bcfca04c0cf1ed07c04819 Mon Sep 17 00:00:00 2001 From: mindyp Date: Tue, 6 Nov 2012 13:47:59 -0800 Subject: Update chips to follow new ux spec for replacement Part of b/7481045 recipient address briefly drawn w/o friendly name Change-Id: I2f3c63f555143c66b3d4f466b60e0ca884d6302b --- .../android/ex/chips/RecipientEditTextView.java | 108 +++++++++++++++------ 1 file changed, 78 insertions(+), 30 deletions(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 9aea16d..215ab60 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -224,6 +224,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements }; + private int mMaxLines; + public RecipientEditTextView(Context context, AttributeSet attrs) { super(context, attrs); setChipDimensions(context, attrs); @@ -263,6 +265,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements addTextChangedListener(mTextWatcher); mGestureDetector = new GestureDetector(context, this); setOnEditorActionListener(this); + mMaxLines = getLineCount(); } @Override @@ -396,7 +399,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements return; } if (mSelectedChip != null - && mSelectedChip.getEntry().getContactId() != RecipientEntry.INVALID_CONTACT) { + && shouldShowEditableText(mSelectedChip)) { clearSelectedChip(); } else { if (getWidth() <= 0) { @@ -507,7 +510,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } - private Bitmap createUnselectedChip(RecipientEntry contact, TextPaint paint, Layout layout) { + private Bitmap createUnselectedChip(RecipientEntry contact, TextPaint paint, Layout layout, + boolean leaveBlankIconSpacer) { // Ellipsize the text so that it takes AT MOST the entire width of the // autocomplete text entry area. Make sure to leave space for padding // on the sides. @@ -531,8 +535,14 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements background.setBounds(0, 0, width, height); background.draw(canvas); - // Don't draw photos for recipients that have been typed in. - if (contact.getContactId() != RecipientEntry.INVALID_CONTACT) { + // Don't draw photos for recipients that have been typed in OR generated on the fly. + long contactId = contact.getContactId(); + boolean drawPhotos = isPhoneQuery() ? + contactId != RecipientEntry.INVALID_CONTACT + : (contactId != RecipientEntry.INVALID_CONTACT + && (contactId != RecipientEntry.GENERATED_CONTACT && + !TextUtils.isEmpty(contact.getDisplayName()))); + if (drawPhotos) { byte[] photoBytes = contact.getPhotoBytes(); // There may not be a photo yet if anything but the first contact address // was selected. @@ -563,8 +573,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements matrix.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); canvas.drawBitmap(photo, matrix, paint); } - } else { - // Don't leave any space for the icon. It isn't being drawn. + } else if (!leaveBlankIconSpacer || isPhoneQuery()) { iconWidth = 0; } paint.setColor(getContext().getResources().getColor(android.R.color.black)); @@ -593,8 +602,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements return height - ((height - textHeight) / 2) - (int)paint.descent(); } - private RecipientChip constructChipSpan(RecipientEntry contact, int offset, boolean pressed) - throws NullPointerException { + private RecipientChip constructChipSpan(RecipientEntry contact, int offset, boolean pressed, + boolean leaveIconSpace) throws NullPointerException { if (mChipBackground == null) { throw new NullPointerException( "Unable to render any chips as setChipDimensions was not called."); @@ -610,7 +619,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements tmpBitmap = createSelectedChip(contact, paint, layout); } else { - tmpBitmap = createUnselectedChip(contact, paint, layout); + tmpBitmap = createUnselectedChip(contact, paint, layout, leaveIconSpace); } // Pass the full text, un-ellipsized, to the chip. @@ -810,7 +819,13 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements mIndividualReplacements = new IndividualReplacementTask(); mIndividualReplacements.execute(new ArrayList( mTemporaryRecipients.subList(0, CHIP_LIMIT))); - + if (mTemporaryRecipients.size() > CHIP_LIMIT) { + mTemporaryRecipients = new ArrayList( + mTemporaryRecipients.subList(CHIP_LIMIT, + mTemporaryRecipients.size())); + } else { + mTemporaryRecipients = null; + } createMoreChip(); } } else { @@ -889,7 +904,14 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements RecipientChip chip = null; try { if (!mNoChips) { - chip = constructChipSpan(entry, start, false); + /* leave space for the contact icon if this is not just an email address */ + chip = constructChipSpan( + entry, + start, + false, + TextUtils.isEmpty(entry.getDisplayName()) + || TextUtils.equals(entry.getDisplayName(), + entry.getDestination())); chipText.setSpan(chip, 0, textLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } catch (NullPointerException e) { @@ -934,6 +956,15 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements // this. display = tokens[0].getName(); if (!TextUtils.isEmpty(display)) { + if (!isPhoneQuery()) { + if (!TextUtils.isEmpty(token)) { + token = token.trim(); + } + char charAt = token.charAt(token.length() - 1); + if (charAt == COMMIT_CHAR_COMMA || charAt == COMMIT_CHAR_SEMICOLON) { + token = token.substring(0, token.length() - 1); + } + } return RecipientEntry.constructGeneratedEntry(display, token); } else { display = tokens[0].getAddress(); @@ -1340,8 +1371,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } chipWasSelected = true; handled = true; - } else if (mSelectedChip != null - && mSelectedChip.getContactId() == RecipientEntry.INVALID_CONTACT) { + } else if (mSelectedChip != null && shouldShowEditableText(mSelectedChip)) { chipWasSelected = true; } } @@ -1526,7 +1556,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements chipText = new SpannableString(displayText); if (!mNoChips) { try { - RecipientChip chip = constructChipSpan(entry, start, pressed); + RecipientChip chip = constructChipSpan(entry, start, pressed, + false /* leave space for contact icon */); chipText.setSpan(chip, 0, textLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); chip.setOriginalText(chipText.toString()); @@ -1576,7 +1607,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements // valid contact, but the destination is invalid, then make this a fake // recipient that is editable. String destination = item.getDestination(); - if (RecipientEntry.isCreatedRecipient(item.getContactId()) + if (!isPhoneQuery() && item.getContactId() == RecipientEntry.GENERATED_CONTACT) { + entry = RecipientEntry.constructGeneratedEntry(item.getDisplayName(), + destination); + } else if (RecipientEntry.isCreatedRecipient(item.getContactId()) && (TextUtils.isEmpty(item.getDisplayName()) || TextUtils.equals(item.getDisplayName(), destination) || (mValidator != null && !mValidator.isValid(destination)))) { @@ -1737,7 +1771,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (!mShouldShrink) { return; } - ImageSpan[] tempMore = getSpannable().getSpans(0, getText().length(), MoreImageSpan.class); if (tempMore.length > 0) { getSpannable().removeSpan(tempMore[0]); @@ -1780,6 +1813,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements chipText.setSpan(moreSpan, 0, chipText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); text.replace(start, end, chipText); mMoreChip = moreSpan; + // If adding the +more chip goes over the limit, resize accordingly. + if (!isPhoneQuery() && getLineCount() > mMaxLines) { + setMaxLines(getLineCount()); + } } /** @@ -1839,7 +1876,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements * just contained an email address. */ private RecipientChip selectChip(RecipientChip currentChip) { - if (currentChip.getContactId() == RecipientEntry.INVALID_CONTACT) { + if (shouldShowEditableText(currentChip)) { CharSequence text = currentChip.getValue(); Editable editable = getText(); removeChip(currentChip); @@ -1856,7 +1893,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (mNoChips) { return null; } - newChip = constructChipSpan(currentChip.getEntry(), start, true); + newChip = constructChipSpan(currentChip.getEntry(), start, true, false); } catch (NullPointerException e) { Log.e(TAG, e.getMessage(), e); return null; @@ -1869,7 +1906,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements editable.setSpan(newChip, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } newChip.setSelected(true); - if (newChip.getEntry().getContactId() == RecipientEntry.INVALID_CONTACT) { + if (shouldShowEditableText(newChip)) { scrollLineIntoView(getLayout().getLineForOffset(getChipStart(newChip))); } showAddress(newChip, mAddressPopup, getWidth(), getContext()); @@ -1881,7 +1918,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements getSpannable().removeSpan(currentChip); RecipientChip newChip; try { - newChip = constructChipSpan(currentChip.getEntry(), start, true); + newChip = constructChipSpan(currentChip.getEntry(), start, true, false); } catch (NullPointerException e) { Log.e(TAG, e.getMessage(), e); return null; @@ -1894,7 +1931,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements editable.setSpan(newChip, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } newChip.setSelected(true); - if (newChip.getEntry().getContactId() == RecipientEntry.INVALID_CONTACT) { + if (shouldShowEditableText(newChip)) { scrollLineIntoView(getLayout().getLineForOffset(getChipStart(newChip))); } showAlternates(newChip, mAlternatesPopup, getWidth(), getContext()); @@ -1903,6 +1940,11 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } } + private boolean shouldShowEditableText(RecipientChip currentChip) { + long contactId = currentChip.getContactId(); + return contactId == RecipientEntry.INVALID_CONTACT + || (!isPhoneQuery() && contactId == RecipientEntry.GENERATED_CONTACT); + } private void showAddress(final RecipientChip currentChip, final ListPopupWindow popup, int width, Context context) { @@ -1947,8 +1989,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements editable.removeSpan(chip); try { if (!mNoChips) { - editable.setSpan(constructChipSpan(chip.getEntry(), start, false), start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + editable.setSpan(constructChipSpan(chip.getEntry(), start, false, false), + start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } catch (NullPointerException e) { Log.e(TAG, e.getMessage(), e); @@ -2093,7 +2135,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } // If the user is editing a chip, don't clear it. if (mSelectedChip != null - && mSelectedChip.getContactId() != RecipientEntry.INVALID_CONTACT) { + && shouldShowEditableText(mSelectedChip)) { setCursorVisible(true); setSelection(getText().length()); clearSelectedChip(); @@ -2285,7 +2327,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (mNoChips) { return null; } - return constructChipSpan(entry, -1, false); + return constructChipSpan(entry, -1, false, + false /*leave space for contact icon */); } catch (NullPointerException e) { Log.e(TAG, e.getMessage(), e); return null; @@ -2376,7 +2419,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements // If there is a match, replace that chip with the matching // chip. final ArrayList originalRecipients = - (ArrayList) params[0]; + (ArrayList) params[0]; ArrayList addresses = new ArrayList(); RecipientChip chip; for (int i = 0; i < originalRecipients.size(); i++) { @@ -2391,13 +2434,18 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (RecipientEntry.isCreatedRecipient(temp.getEntry().getContactId()) && getSpannable().getSpanStart(temp) != -1) { // Replace this. - final RecipientEntry entry = createValidatedEntry(entries.get( - tokenizeAddress(temp.getEntry().getDestination()).toLowerCase())); - if (entry != null) { + RecipientEntry entry = createValidatedEntry(entries.get(tokenizeAddress( + temp.getEntry().getDestination()).toLowerCase())); + if (entry == null && !isPhoneQuery()) { + entry = RecipientEntry.constructFakeEntry(Rfc822Tokenizer.tokenize(temp + .getEntry().getDestination())[0].getAddress()); + } + final RecipientEntry tempEntry = entry; + if (tempEntry != null) { mHandler.post(new Runnable() { @Override public void run() { - replaceChip(temp, entry); + replaceChip(temp, tempEntry); } }); } -- cgit v1.2.3 From dab17fcff4efe640287a8cce7f82bd305e2c1fcf Mon Sep 17 00:00:00 2001 From: mindyp Date: Wed, 7 Nov 2012 08:58:06 -0800 Subject: Make sure that the last "fake entry" chip is correctly committed Fix logic to correctly determine that this "recipient chip" is really text Fixes part of b/7481045 recipient address briefly drawn w/o friendly name Change-Id: I4c5244581a4fce5de58d6d9c510e1df16674c338 --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 215ab60..7a3c619 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -398,8 +398,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (mTokenizer == null) { return; } - if (mSelectedChip != null - && shouldShowEditableText(mSelectedChip)) { + long contactId = mSelectedChip != null ? mSelectedChip.getEntry().getContactId() : -1; + if (mSelectedChip != null && contactId != RecipientEntry.INVALID_CONTACT + && (!isPhoneQuery() && contactId != RecipientEntry.GENERATED_CONTACT)) { clearSelectedChip(); } else { if (getWidth() <= 0) { -- cgit v1.2.3 From bc8820f28fae94349e41ad09e166b0537ddd1377 Mon Sep 17 00:00:00 2001 From: mindyp Date: Wed, 7 Nov 2012 09:33:11 -0800 Subject: Make sure that we take the existng temporary contact, where available. Temporary contact entry will give us display name and address if it has it when there is no contact match Fixes part of b/7481045 recipient address briefly drawn w/o friendly name Change-Id: Id5cf6b770d1179c81d9c9b808af4681e632d18a7 --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 7a3c619..011b1e9 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -2437,9 +2437,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements // Replace this. RecipientEntry entry = createValidatedEntry(entries.get(tokenizeAddress( temp.getEntry().getDestination()).toLowerCase())); + // If we don't have a validated contact match, just use the + // entry as it existed before. if (entry == null && !isPhoneQuery()) { - entry = RecipientEntry.constructFakeEntry(Rfc822Tokenizer.tokenize(temp - .getEntry().getDestination())[0].getAddress()); + entry = temp.getEntry(); } final RecipientEntry tempEntry = entry; if (tempEntry != null) { -- cgit v1.2.3 From e719fc8a822b3db583f82a6de1b8690267e14d96 Mon Sep 17 00:00:00 2001 From: mindyp Date: Thu, 8 Nov 2012 16:30:27 -0800 Subject: dont replace the text in the text field when editing a fake or generated entry We are editing the entire text in there, and that includes the display name and any other information...so just remove the span This means we dont trigger a text change that triggers a scroll Fixes b/7499873 Odd scroll when touch non-contact chips with quote text enabled Change-Id: I0c537e7fec663abe3cec96a5b59bc52caa009a30 --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 011b1e9..b460a4d 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -427,7 +427,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements int whatEnd = mTokenizer.findTokenEnd(text, start); // This token was already tokenized, so skip past the ending token. if (whatEnd < text.length() && text.charAt(whatEnd) == ',') { - whatEnd++; + whatEnd = movePastTerminators(whatEnd); } // In the middle of chip; treat this as an edit // and commit the whole token. @@ -1117,6 +1117,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements int whatEnd = mTokenizer.findTokenEnd(getText(), start); // In the middle of chip; treat this as an edit // and commit the whole token. + whatEnd = movePastTerminators(whatEnd); if (whatEnd != getSelectionEnd()) { handleEdit(start, whatEnd); return true; @@ -1880,8 +1881,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (shouldShowEditableText(currentChip)) { CharSequence text = currentChip.getValue(); Editable editable = getText(); - removeChip(currentChip); - editable.append(text); + getSpannable().removeSpan(currentChip); setCursorVisible(true); setSelection(editable.length()); return new RecipientChip(null, RecipientEntry.constructFakeEntry((String) text), -1); @@ -2208,7 +2208,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements private void scrollBottomIntoView() { if (mScrollView != null) { - mScrollView.scrollBy(0, (int)(getLineCount() * mChipHeight)); + mScrollView.scrollBy(0, (int) (getLineCount() * mChipHeight)); } } -- cgit v1.2.3 From 99ea997e237f6941bed7bdfbc221ad78643650c5 Mon Sep 17 00:00:00 2001 From: mindyp Date: Fri, 9 Nov 2012 14:05:19 -0800 Subject: Reduce time until first revision of a chip is drawn. Means less time showing plain text. replace call is expensive. Change-Id: I1be571af78497c2dfff724b612d60ededc98ff36 --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index b460a4d..4568b2c 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -897,8 +897,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements RecipientEntry entry = createTokenizedEntry(token); if (entry != null) { String destText = createAddressText(entry); - // Always leave a blank space at the end of a chip. - int textLength = destText.length() - 1; SpannableString chipText = new SpannableString(destText); int end = getSelectionEnd(); int start = mTokenizer != null ? mTokenizer.findTokenStart(getText(), end) : 0; @@ -913,12 +911,11 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements TextUtils.isEmpty(entry.getDisplayName()) || TextUtils.equals(entry.getDisplayName(), entry.getDestination())); - chipText.setSpan(chip, 0, textLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } catch (NullPointerException e) { Log.e(TAG, e.getMessage(), e); } - editable.replace(tokenStart, tokenEnd, chipText); + editable.setSpan(chip, tokenStart, tokenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // Add this chip to the list of entries "to replace" if (chip != null) { if (mTemporaryRecipients == null) { @@ -2391,11 +2388,11 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements end = oldText.getSpanEnd(chip); oldText.removeSpan(chip); RecipientChip replacement = replacements.get(i); - // Trim any whitespace, as we will already have - // it added if these are replacement chips. + // Make sure we always have just 1 space at the + // end to separate this chip from the next chip. SpannableString displayText = new SpannableString( - createAddressText(replacement.getEntry()).trim()); - displayText.setSpan(replacement, 0, displayText.length(), + createAddressText(replacement.getEntry()).trim() + " "); + displayText.setSpan(replacement, 0, displayText.length()-1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // Replace the old text we found with with the new display text, // which now may also contain the display name of the recipient. -- cgit v1.2.3 From f5ac32862370c6dd004baa0ac838bced8794a0d8 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Thu, 15 Nov 2012 13:57:41 -0800 Subject: SMS text messaging omits numbers in parentheses Bug 7355280 Very localized fix. Tweak the phone number matching pattern to handle a "1" before parens. This change was originally incorporated in MR1, but wiped out by some automerger change. Bringing the change back for MR1.1. Change-Id: Ifd11762fb7253fab69ca912dff6b62c5673bf216 --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 011b1e9..5327389 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -88,6 +88,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * RecipientEditTextView is an auto complete text view for use with applications @@ -194,6 +195,15 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements private boolean mDragEnabled = false; + // This pattern comes from android.util.Patterns. It has been tweaked to handle a "1" before + // parens, so numbers such as "1 (425) 222-2342" match. + private static final Pattern PHONE_PATTERN + = Pattern.compile( // sdd = space, dot, or dash + "(\\+[0-9]+[\\- \\.]*)?" // +* + + "(1?[ ]*\\([0-9]+\\)[\\- \\.]*)?" // 1()* + + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // + + + private final Runnable mAddTextWatcher = new Runnable() { @Override public void run() { @@ -938,7 +948,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements return false; } - Matcher match = Patterns.PHONE.matcher(number); + Matcher match = PHONE_PATTERN.matcher(number); return match.matches(); } -- cgit v1.2.3 From 3665fb7aaf0948f694e2d28ab76e1f5e4befb45d Mon Sep 17 00:00:00 2001 From: mindyp Date: Fri, 14 Dec 2012 10:40:51 -0800 Subject: Scroll when result of a contacts lookup appear Fixes b/7727257 Jank when replying to or forwarding a message in gmail Change-Id: I620fb31adcb80ca7a6a86c64c987969bc630429d --- .../com/android/ex/chips/BaseRecipientAdapter.java | 15 +++++ .../android/ex/chips/RecipientEditTextView.java | 78 ++++++++++++++++++---- 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/chips/src/com/android/ex/chips/BaseRecipientAdapter.java b/chips/src/com/android/ex/chips/BaseRecipientAdapter.java index c0cfa19..c981728 100644 --- a/chips/src/com/android/ex/chips/BaseRecipientAdapter.java +++ b/chips/src/com/android/ex/chips/BaseRecipientAdapter.java @@ -499,6 +499,8 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter private final DelayedMessageHandler mDelayedMessageHandler = new DelayedMessageHandler(); + private EntriesUpdatedObserver mEntriesUpdatedObserver; + /** * Constructor for email queries. */ @@ -706,9 +708,14 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter return entries; } + public void registerUpdateObserver(EntriesUpdatedObserver observer) { + mEntriesUpdatedObserver = observer; + } + /** Resets {@link #mEntries} and notify the event to its parent ListView. */ private void updateEntries(List newEntries) { mEntries = newEntries; + mEntriesUpdatedObserver.onChanged(newEntries); notifyDataSetChanged(); } @@ -967,4 +974,12 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter protected int getPhotoId() { return android.R.id.icon; } + + /** + * Interface called before the BaseRecipientAdapter updates recipient + * results in the popup window. + */ + protected interface EntriesUpdatedObserver { + public void onChanged(List entries); + } } diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 564bfe1..525f75d 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -54,6 +54,7 @@ import android.text.util.Rfc822Token; import android.text.util.Rfc822Tokenizer; import android.util.AttributeSet; import android.util.Log; +import android.util.TypedValue; import android.util.Patterns; import android.view.ActionMode; import android.view.ActionMode.Callback; @@ -72,6 +73,7 @@ import android.view.inputmethod.InputConnection; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; +import android.widget.Filterable; import android.widget.ListAdapter; import android.widget.ListPopupWindow; import android.widget.ListView; @@ -86,6 +88,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -236,6 +239,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements private int mMaxLines; + private static int sExcessTopPadding = -1; + + private int mActionBarHeight; + public RecipientEditTextView(Context context, AttributeSet attrs) { super(context, attrs); setChipDimensions(context, attrs); @@ -399,6 +406,44 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } } + private int getExcessTopPadding() { + if (sExcessTopPadding == -1) { + sExcessTopPadding = (int) mChipHeight; + } + return sExcessTopPadding; + } + + public void setAdapter(T adapter) { + super.setAdapter(adapter); + ((BaseRecipientAdapter) adapter) + .registerUpdateObserver(new BaseRecipientAdapter.EntriesUpdatedObserver() { + @Override + public void onChanged(List entries) { + // Scroll the chips field to the top of the screen so + // that the user can see as many results as possible. + if (entries != null && entries.size() > 0) { + scrollBottomIntoView(); + } + } + }); + } + + private void scrollBottomIntoView() { + if (mScrollView != null && mShouldShrink) { + int[] location = new int[2]; + getLocationOnScreen(location); + int height = getHeight(); + int currentPos = location[1] + height; + // Desired position shows at least 1 line of chips below the action + // bar. We add excess padding to make sure this is always below other + // content. + int desiredPos = (int) mChipHeight + mActionBarHeight + getExcessTopPadding(); + if (currentPos > desiredPos) { + mScrollView.scrollBy(0, currentPos - desiredPos); + } + } + } + @Override public void performValidation() { // Do nothing. Chips handles its own validation. @@ -711,6 +756,11 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements mInvalidChipBackground = r.getDrawable(R.drawable.chip_background_invalid); } mLineSpacingExtra = context.getResources().getDimension(R.dimen.line_spacing_extra); + TypedValue tv = new TypedValue(); + if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { + mActionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources() + .getDisplayMetrics()); + } a.recycle(); } @@ -1302,7 +1352,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements */ @Override protected void performFiltering(CharSequence text, int keyCode) { - if (enoughToFilter() && !isCompletedToken(text)) { + boolean isCompletedToken = isCompletedToken(text); + if (enoughToFilter() && !isCompletedToken) { int end = getSelectionEnd(); int start = mTokenizer.findTokenStart(text, end); // If this is a RecipientChip, don't filter @@ -1312,6 +1363,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (chips != null && chips.length > 0) { return; } + } else if (isCompletedToken) { + return; } super.performFiltering(text, keyCode); } @@ -1392,7 +1445,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements private void scrollLineIntoView(int line) { if (mScrollView != null) { - mScrollView.scrollBy(0, calculateOffsetFromBottom(line)); + mScrollView.smoothScrollBy(0, calculateOffsetFromBottom(line)); } } @@ -1888,10 +1941,17 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (shouldShowEditableText(currentChip)) { CharSequence text = currentChip.getValue(); Editable editable = getText(); - getSpannable().removeSpan(currentChip); + Spannable spannable = getSpannable(); + int spanStart = spannable.getSpanStart(currentChip); + int spanEnd = spannable.getSpanEnd(currentChip); + spannable.removeSpan(currentChip); + editable.delete(spanStart, spanEnd); setCursorVisible(true); setSelection(editable.length()); - return new RecipientChip(null, RecipientEntry.constructFakeEntry((String) text), -1); + editable.append(text); + return constructChipSpan( + RecipientEntry.constructFakeEntry((String) text), + getSelectionStart(), true, false); } else if (currentChip.getContactId() == RecipientEntry.GENERATED_CONTACT) { int start = getChipStart(currentChip); int end = getChipEnd(currentChip); @@ -2183,7 +2243,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements public void onTextChanged(CharSequence s, int start, int before, int count) { // This is a delete; check to see if the insertion point is on a space // following a chip. - if (before > count) { + if (before - count == 1) { // If the item deleted is a space, and the thing before the // space is a chip, delete the entire span. int selStart = getSelectionStart(); @@ -2202,8 +2262,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements editable.delete(tokenStart, tokenEnd); getSpannable().removeSpan(repl[0]); } - } else if (count > before) { - scrollBottomIntoView(); } } @@ -2213,12 +2271,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } } - private void scrollBottomIntoView() { - if (mScrollView != null) { - mScrollView.scrollBy(0, (int) (getLineCount() * mChipHeight)); - } - } - /** * Handles pasting a {@link ClipData} to this {@link RecipientEditTextView}. */ -- cgit v1.2.3 From 8f7bdab470c48a5e53c9a8a54ae9eb7f59827a32 Mon Sep 17 00:00:00 2001 From: Paul Westbrook Date: Fri, 14 Dec 2012 16:35:35 -0800 Subject: Fix problem where part of wrong photo shows Fix a problem when swiping through a few image attachments where, when reaching the end, part of the N-1 photo is shown while the blue glow is being shown on the right side Bug: 7745114 Cherry-pick of https://googleplex-android-review.googlesource.com/#/c/260544/ Change-Id: Ic7d8b4213303a7e06c902b117e1e68b40bd8e1c3 --- photoviewer/res/values/dimen.xml | 1 + photoviewer/src/com/android/ex/photo/PhotoViewActivity.java | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/photoviewer/res/values/dimen.xml b/photoviewer/res/values/dimen.xml index c1b8b90..754c99b 100644 --- a/photoviewer/res/values/dimen.xml +++ b/photoviewer/res/values/dimen.xml @@ -21,4 +21,5 @@ 1dip 200dip 48dip + 32dip diff --git a/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java b/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java index 2a24e1f..6f126b4 100644 --- a/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java +++ b/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java @@ -25,6 +25,7 @@ import android.app.Fragment; import android.app.LoaderManager.LoaderCallbacks; import android.content.Intent; import android.content.Loader; +import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.os.Build; @@ -183,18 +184,19 @@ public class PhotoViewActivity extends Activity implements // Create the adapter and add the view pager mAdapter = new PhotoPagerAdapter(this, getFragmentManager(), null); + final Resources resources = getResources(); mViewPager = (PhotoViewPager) findViewById(R.id.photo_view_pager); mViewPager.setAdapter(mAdapter); mViewPager.setOnPageChangeListener(this); mViewPager.setOnInterceptTouchListener(this); + mViewPager.setPageMargin(resources.getDimensionPixelSize(R.dimen.photo_page_margin)); // Kick off the loader getLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this); final ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); - mActionBarHideDelayTime = getResources().getInteger( - R.integer.action_bar_delay_time_in_millis); + mActionBarHideDelayTime = resources.getInteger(R.integer.action_bar_delay_time_in_millis); actionBar.addOnMenuVisibilityListener(this); actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); } -- cgit v1.2.3 From 09bb480c04705138b7329d425181a9869b34f8e9 Mon Sep 17 00:00:00 2001 From: mindyp Date: Mon, 17 Dec 2012 12:04:01 -0800 Subject: Eliminate jank when the user deletes a character thereby removing all contact results in the popup. part of b/7727257] Jank when replying to or forwarding a message in gmail Change-Id: If95716847260d802e527a4ad012ea7f8085d6930 --- chips/src/com/android/ex/chips/RecipientEditTextView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 525f75d..93ca4e8 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -408,7 +408,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements private int getExcessTopPadding() { if (sExcessTopPadding == -1) { - sExcessTopPadding = (int) mChipHeight; + sExcessTopPadding = (int) (mChipHeight + mLineSpacingExtra); } return sExcessTopPadding; } -- cgit v1.2.3