am 92be9d34: (-s ours) Reconcile with jb-mr1-release - do not merge
* commit '92be9d34bf220d26f49ed1b328a84d3cad84d21f':
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 @@
private final DelayedMessageHandler mDelayedMessageHandler = new DelayedMessageHandler();
+ private EntriesUpdatedObserver mEntriesUpdatedObserver;
+
/**
* Constructor for email queries.
*/
@@ -706,9 +708,14 @@
return entries;
}
+ public void registerUpdateObserver(EntriesUpdatedObserver observer) {
+ mEntriesUpdatedObserver = observer;
+ }
+
/** Resets {@link #mEntries} and notify the event to its parent ListView. */
private void updateEntries(List<RecipientEntry> newEntries) {
mEntries = newEntries;
+ mEntriesUpdatedObserver.onChanged(newEntries);
notifyDataSetChanged();
}
@@ -967,4 +974,12 @@
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<RecipientEntry> entries);
+ }
}
diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java
index 011b1e9..93ca4e8 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.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.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,8 +88,10 @@
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;
/**
* RecipientEditTextView is an auto complete text view for use with applications
@@ -194,6 +198,15 @@
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]+[\\- \\.]*)?" // +<digits><sdd>*
+ + "(1?[ ]*\\([0-9]+\\)[\\- \\.]*)?" // 1(<digits>)<sdd>*
+ + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit>
+
+
private final Runnable mAddTextWatcher = new Runnable() {
@Override
public void run() {
@@ -226,6 +239,10 @@
private int mMaxLines;
+ private static int sExcessTopPadding = -1;
+
+ private int mActionBarHeight;
+
public RecipientEditTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setChipDimensions(context, attrs);
@@ -389,6 +406,44 @@
}
}
+ private int getExcessTopPadding() {
+ if (sExcessTopPadding == -1) {
+ sExcessTopPadding = (int) (mChipHeight + mLineSpacingExtra);
+ }
+ return sExcessTopPadding;
+ }
+
+ public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
+ super.setAdapter(adapter);
+ ((BaseRecipientAdapter) adapter)
+ .registerUpdateObserver(new BaseRecipientAdapter.EntriesUpdatedObserver() {
+ @Override
+ public void onChanged(List<RecipientEntry> 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.
@@ -427,7 +482,7 @@
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.
@@ -701,6 +756,11 @@
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();
}
@@ -897,8 +957,6 @@
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 +971,11 @@
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) {
@@ -938,7 +995,7 @@
return false;
}
- Matcher match = Patterns.PHONE.matcher(number);
+ Matcher match = PHONE_PATTERN.matcher(number);
return match.matches();
}
@@ -1117,6 +1174,7 @@
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;
@@ -1294,7 +1352,8 @@
*/
@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
@@ -1304,6 +1363,8 @@
if (chips != null && chips.length > 0) {
return;
}
+ } else if (isCompletedToken) {
+ return;
}
super.performFiltering(text, keyCode);
}
@@ -1384,7 +1445,7 @@
private void scrollLineIntoView(int line) {
if (mScrollView != null) {
- mScrollView.scrollBy(0, calculateOffsetFromBottom(line));
+ mScrollView.smoothScrollBy(0, calculateOffsetFromBottom(line));
}
}
@@ -1880,11 +1941,17 @@
if (shouldShowEditableText(currentChip)) {
CharSequence text = currentChip.getValue();
Editable editable = getText();
- removeChip(currentChip);
- editable.append(text);
+ 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);
@@ -2176,7 +2243,7 @@
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();
@@ -2195,8 +2262,6 @@
editable.delete(tokenStart, tokenEnd);
getSpannable().removeSpan(repl[0]);
}
- } else if (count > before) {
- scrollBottomIntoView();
}
}
@@ -2206,12 +2271,6 @@
}
}
- private void scrollBottomIntoView() {
- if (mScrollView != null) {
- mScrollView.scrollBy(0, (int)(getLineCount() * mChipHeight));
- }
- }
-
/**
* Handles pasting a {@link ClipData} to this {@link RecipientEditTextView}.
*/
@@ -2391,11 +2450,11 @@
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.
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 @@
<dimen name="photo_crop_stroke_width">1dip</dimen>
<dimen name="photo_preview_size">200dip</dimen>
<dimen name="retry_button_size">48dip</dimen>
+ <dimen name="photo_page_margin">32dip</dimen>
</resources>
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.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 @@
// 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);
}