Merge "Store shortcut action on rotation"
diff --git a/src/com/android/contacts/ContactPhotoManager.java b/src/com/android/contacts/ContactPhotoManager.java
index 7c54e80..f53766d 100644
--- a/src/com/android/contacts/ContactPhotoManager.java
+++ b/src/com/android/contacts/ContactPhotoManager.java
@@ -177,6 +177,14 @@
public abstract void refreshCache();
/**
+ * Stores the given bitmap directly in the LRU bitmap cache.
+ * @param photoUri The URI of the photo (for future requests).
+ * @param bitmap The bitmap.
+ * @param photoBytes The bytes that were parsed to create the bitmap.
+ */
+ public abstract void cacheBitmap(Uri photoUri, Bitmap bitmap, byte[] photoBytes);
+
+ /**
* Initiates a background process that over time will fill up cache with
* preload photos.
*/
@@ -649,6 +657,14 @@
mBitmapHolderCache.put(key, holder);
}
+ @Override
+ public void cacheBitmap(Uri photoUri, Bitmap bitmap, byte[] photoBytes) {
+ Request request = Request.createFromUri(photoUri, true, false, DEFAULT_AVATER);
+ BitmapHolder holder = new BitmapHolder(photoBytes);
+ mBitmapHolderCache.put(request.getKey(), holder);
+ mBitmapCache.put(request, bitmap);
+ }
+
/**
* Populates an array of photo IDs that need to be loaded.
*/
diff --git a/src/com/android/contacts/activities/PhotoSelectionActivity.java b/src/com/android/contacts/activities/PhotoSelectionActivity.java
index 73a85eb..de129cb 100644
--- a/src/com/android/contacts/activities/PhotoSelectionActivity.java
+++ b/src/com/android/contacts/activities/PhotoSelectionActivity.java
@@ -15,6 +15,7 @@
*/
package com.android.contacts.activities;
+import com.android.contacts.ContactPhotoManager;
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
import com.android.contacts.detail.PhotoSelectionHandler;
@@ -30,6 +31,7 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.View;
@@ -58,8 +60,8 @@
private static final String KEY_SUB_ACTIVITY_IN_PROGRESS = "subinprogress";
- /** Intent extra to get the photo bitmap. */
- public static final String PHOTO_BITMAP = "photo_bitmap";
+ /** Intent extra to get the photo URI. */
+ public static final String PHOTO_URI = "photo_uri";
/** Intent extra to get the entity delta list. */
public static final String ENTITY_DELTA_LIST = "entity_delta_list";
@@ -80,8 +82,10 @@
/** Source bounds of the image that was clicked on. */
private Rect mSourceBounds;
- /** The photo bitmap. */
- private Bitmap mPhotoBitmap;
+ /**
+ * The photo URI. May be null, in which case the default avatar will be used.
+ */
+ private Uri mPhotoUri;
/** Entity delta list of the contact. */
private EntityDeltaList mState;
@@ -149,7 +153,7 @@
// Pull data out of the intent.
final Intent intent = getIntent();
- mPhotoBitmap = intent.getParcelableExtra(PHOTO_BITMAP);
+ mPhotoUri = intent.getParcelableExtra(PHOTO_URI);
mState = (EntityDeltaList) intent.getParcelableExtra(ENTITY_DELTA_LIST);
mIsProfile = intent.getBooleanExtra(IS_PROFILE, false);
mIsDirectoryContact = intent.getBooleanExtra(IS_DIRECTORY_CONTACT, false);
@@ -193,7 +197,12 @@
/**
* Builds a well-formed intent for invoking this activity.
* @param context The context.
- * @param photoBitmap The bitmap of the current photo.
+ * @param photoUri The URI of the current photo (may be null, in which case the default
+ * avatar image will be displayed).
+ * @param photoBitmap The bitmap of the current photo (may be null, in which case the default
+ * avatar image will be displayed).
+ * @param photoBytes The bytes for the current photo (may be null, in which case the default
+ * avatar image will be displayed).
* @param photoBounds The pixel bounds of the current photo.
* @param delta The entity delta list for the contact.
* @param isProfile Whether the contact is the user's profile.
@@ -202,11 +211,13 @@
* this should be true for phones, and false for tablets).
* @return An intent that can be used to invoke the photo selection activity.
*/
- public static Intent buildIntent(Context context, Bitmap photoBitmap, Rect photoBounds,
- EntityDeltaList delta, boolean isProfile, boolean isDirectoryContact,
- boolean expandPhotoOnClick) {
+ public static Intent buildIntent(Context context, Uri photoUri, Bitmap photoBitmap,
+ byte[] photoBytes, Rect photoBounds, EntityDeltaList delta, boolean isProfile,
+ boolean isDirectoryContact, boolean expandPhotoOnClick) {
Intent intent = new Intent(context, PhotoSelectionActivity.class);
- intent.putExtra(PHOTO_BITMAP, photoBitmap);
+ if (photoUri != null && photoBitmap != null && photoBytes != null) {
+ intent.putExtra(PHOTO_URI, photoUri);
+ }
intent.setSourceBounds(photoBounds);
intent.putExtra(ENTITY_DELTA_LIST, (Parcelable) delta);
intent.putExtra(IS_PROFILE, isProfile);
@@ -233,48 +244,55 @@
}
private void displayPhoto() {
- if (mPhotoBitmap != null) {
- final int[] pos = new int[2];
- mBackdrop.getLocationOnScreen(pos);
- LayoutParams layoutParams = new LayoutParams(mSourceBounds.width(),
- mSourceBounds.height());
- mOriginalPos.left = mSourceBounds.left - pos[0];
- mOriginalPos.top = mSourceBounds.top - pos[1];
- mOriginalPos.right = mOriginalPos.left + mSourceBounds.width();
- mOriginalPos.bottom = mOriginalPos.top + mSourceBounds.height();
- layoutParams.setMargins(mOriginalPos.left, mOriginalPos.top, mOriginalPos.right,
- mOriginalPos.bottom);
- mPhotoStartParams = layoutParams;
- mPhotoView.setLayoutParams(layoutParams);
- mPhotoView.requestLayout();
-
- mPhotoView.setImageBitmap(mPhotoBitmap);
- mPhotoView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if (mAnimationPending) {
- mAnimationPending = false;
- PropertyValuesHolder pvhLeft =
- PropertyValuesHolder.ofInt("left", mOriginalPos.left, left);
- PropertyValuesHolder pvhTop =
- PropertyValuesHolder.ofInt("top", mOriginalPos.top, top);
- PropertyValuesHolder pvhRight =
- PropertyValuesHolder.ofInt("right", mOriginalPos.right, right);
- PropertyValuesHolder pvhBottom =
- PropertyValuesHolder.ofInt("bottom", mOriginalPos.bottom, bottom);
- ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(mPhotoView,
- pvhLeft, pvhTop, pvhRight, pvhBottom).setDuration(
- PHOTO_EXPAND_DURATION);
- if (mAnimationListener != null) {
- anim.addListener(mAnimationListener);
- }
- anim.start();
- }
- }
- });
- attachPhotoHandler();
+ // Load the photo.
+ if (mPhotoUri != null) {
+ // If we have a URI, the bitmap should be cached directly.
+ ContactPhotoManager.getInstance(this).loadPhoto(mPhotoView, mPhotoUri, true, false);
+ } else {
+ // Fall back to avatar image.
+ mPhotoView.setImageResource(ContactPhotoManager.getDefaultAvatarResId(true, false));
}
+
+ // Animate the photo view into its end location.
+ final int[] pos = new int[2];
+ mBackdrop.getLocationOnScreen(pos);
+ LayoutParams layoutParams = new LayoutParams(mSourceBounds.width(),
+ mSourceBounds.height());
+ mOriginalPos.left = mSourceBounds.left - pos[0];
+ mOriginalPos.top = mSourceBounds.top - pos[1];
+ mOriginalPos.right = mOriginalPos.left + mSourceBounds.width();
+ mOriginalPos.bottom = mOriginalPos.top + mSourceBounds.height();
+ layoutParams.setMargins(mOriginalPos.left, mOriginalPos.top, mOriginalPos.right,
+ mOriginalPos.bottom);
+ mPhotoStartParams = layoutParams;
+ mPhotoView.setLayoutParams(layoutParams);
+ mPhotoView.requestLayout();
+
+ mPhotoView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ if (mAnimationPending) {
+ mAnimationPending = false;
+ PropertyValuesHolder pvhLeft =
+ PropertyValuesHolder.ofInt("left", mOriginalPos.left, left);
+ PropertyValuesHolder pvhTop =
+ PropertyValuesHolder.ofInt("top", mOriginalPos.top, top);
+ PropertyValuesHolder pvhRight =
+ PropertyValuesHolder.ofInt("right", mOriginalPos.right, right);
+ PropertyValuesHolder pvhBottom =
+ PropertyValuesHolder.ofInt("bottom", mOriginalPos.bottom, bottom);
+ ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(mPhotoView,
+ pvhLeft, pvhTop, pvhRight, pvhBottom).setDuration(
+ PHOTO_EXPAND_DURATION);
+ if (mAnimationListener != null) {
+ anim.addListener(mAnimationListener);
+ }
+ anim.start();
+ }
+ }
+ });
+ attachPhotoHandler();
}
private LayoutParams getPhotoEndParams() {
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index 588e6ff..912d7fb 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -29,7 +29,6 @@
import com.android.contacts.util.StreamItemPhotoEntry;
import com.google.common.annotations.VisibleForTesting;
-import android.app.Activity;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
@@ -45,7 +44,6 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Parcelable;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.Data;
@@ -228,7 +226,7 @@
// Set up the photo to display a full-screen photo selection activity when clicked.
OnClickListener clickListener = new PhotoClickListener(context, contactData, bitmap,
- expandPhotoOnClick);
+ photo, expandPhotoOnClick);
photoView.setOnClickListener(clickListener);
return clickListener;
}
@@ -238,12 +236,14 @@
private final Context mContext;
private final Result mContactData;
private final Bitmap mPhotoBitmap;
+ private final byte[] mPhotoBytes;
private final boolean mExpandPhotoOnClick;
public PhotoClickListener(Context context, Result contactData, Bitmap photoBitmap,
- boolean expandPhotoOnClick) {
+ byte[] photoBytes, boolean expandPhotoOnClick) {
mContext = context;
mContactData = contactData;
mPhotoBitmap = photoBitmap;
+ mPhotoBytes = photoBytes;
mExpandPhotoOnClick = expandPhotoOnClick;
}
@@ -266,9 +266,16 @@
rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
+ Uri photoUri = null;
+ if (mContactData.getPhotoUri() != null) {
+ photoUri = Uri.parse(mContactData.getPhotoUri());
+ }
Intent photoSelectionIntent = PhotoSelectionActivity.buildIntent(mContext,
- mPhotoBitmap, rect, delta, mContactData.isUserProfile(),
+ photoUri, mPhotoBitmap, mPhotoBytes, rect, delta, mContactData.isUserProfile(),
mContactData.isDirectoryEntry(), mExpandPhotoOnClick);
+ // Cache the bitmap directly, so the activity can pull it from the photo manager.
+ ContactPhotoManager.getInstance(mContext).cacheBitmap(photoUri, mPhotoBitmap,
+ mPhotoBytes);
mContext.startActivity(photoSelectionIntent);
}
}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index f3d7451..8f77371 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -133,13 +133,6 @@
private static final String KEY_CONTACT_URI = "contactUri";
private static final String KEY_LIST_STATE = "liststate";
- // TODO: Make maxLines a field in {@link DataKind}
- private static final int WEBSITE_MAX_LINES = 1;
- private static final int SIP_ADDRESS_MAX_LINES= 1;
- private static final int POSTAL_ADDRESS_MAX_LINES = 10;
- private static final int GROUP_MAX_LINES = 10;
- private static final int NOTE_MAX_LINES = 100;
-
private Context mContext;
private View mView;
private OnScrollListener mVerticalScrollListener;
@@ -454,7 +447,7 @@
mStaticPhotoContainer.setVisibility(View.VISIBLE);
ImageView photoView = (ImageView) mStaticPhotoContainer.findViewById(R.id.photo);
OnClickListener listener = ContactDetailDisplayUtils.setPhoto(mContext,
- mContactData, photoView, !PhoneCapabilityTester.isUsingTwoPanes(mContext));
+ mContactData, photoView, false);
if (mPhotoTouchOverlay != null) {
mPhotoTouchOverlay.setVisibility(View.VISIBLE);
mPhotoTouchOverlay.setOnClickListener(listener);
@@ -595,6 +588,7 @@
final DetailViewEntry entry = DetailViewEntry.fromValues(mContext, mimeType, kind,
dataId, entryValues, mContactData.isDirectoryEntry(),
mContactData.getDirectoryId());
+ entry.maxLines = kind.maxLinesForDisplay;
final boolean hasData = !TextUtils.isEmpty(entry.data);
Integer superPrimary = entryValues.getAsInteger(Data.IS_SUPER_PRIMARY);
@@ -651,11 +645,11 @@
mContactData.getDirectoryId());
buildImActions(mContext, imEntry, entryValues);
imEntry.applyStatus(status, false);
+ imEntry.maxLines = imKind.maxLinesForDisplay;
mImEntries.add(imEntry);
}
} else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build postal entries
- entry.maxLines = POSTAL_ADDRESS_MAX_LINES;
entry.intent = StructuredPostalUtils.getViewPostalAddressIntent(entry.data);
mPostalEntries.add(entry);
} else if (Im.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
@@ -687,12 +681,10 @@
} else if (Note.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build note entries
entry.uri = null;
- entry.maxLines = NOTE_MAX_LINES;
mNoteEntries.add(entry);
} else if (Website.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build Website entries
entry.uri = null;
- entry.maxLines = WEBSITE_MAX_LINES;
try {
WebAddress webAddress = new WebAddress(entry.data);
entry.intent = new Intent(Intent.ACTION_VIEW,
@@ -704,7 +696,6 @@
} else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build SipAddress entries
entry.uri = null;
- entry.maxLines = SIP_ADDRESS_MAX_LINES;
if (mHasSip) {
entry.intent = ContactsUtils.getCallIntent(
Uri.fromParts(Constants.SCHEME_SIP, entry.data, null));
@@ -768,7 +759,6 @@
entry.mimetype = GroupMembership.MIMETYPE;
entry.kind = mContext.getString(R.string.groupsLabel);
entry.data = sb.toString();
- entry.maxLines = GROUP_MAX_LINES;
mGroupEntries.add(entry);
}
}
diff --git a/src/com/android/contacts/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index 4a5a502..475e172 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -131,7 +131,9 @@
@Override
public boolean isEmpty() {
- return TextUtils.isEmpty(mDateView.getText());
+ final EditField editField = getKind().fieldList.get(0);
+ final String column = editField.column;
+ return TextUtils.isEmpty(getEntry().getAsString(column));
}
@Override
@@ -243,6 +245,7 @@
} else {
resultString = kind.dateFormatWithYear.format(outCalendar.getTime());
}
+
onFieldChanged(column, resultString);
rebuildDateView();
}
diff --git a/src/com/android/contacts/editor/PhoneticNameEditorView.java b/src/com/android/contacts/editor/PhoneticNameEditorView.java
index 59545d4..5e47d89 100644
--- a/src/com/android/contacts/editor/PhoneticNameEditorView.java
+++ b/src/com/android/contacts/editor/PhoneticNameEditorView.java
@@ -202,6 +202,11 @@
// phonetic name.
super.onFieldChanged(column, value);
}
+ } else {
+ // All fields are always visible, so we don't have to worry about blocking updates
+ // from onRestoreInstanceState() from hidden fields. Always call into the superclass
+ // to update the field and rebuild the underlying phonetic name.
+ super.onFieldChanged(column, value);
}
}
diff --git a/src/com/android/contacts/model/BaseAccountType.java b/src/com/android/contacts/model/BaseAccountType.java
index cd113eb..4d82ece 100644
--- a/src/com/android/contacts/model/BaseAccountType.java
+++ b/src/com/android/contacts/model/BaseAccountType.java
@@ -79,6 +79,12 @@
protected static final int FLAGS_RELATION = EditorInfo.TYPE_CLASS_TEXT
| EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
+ // Specify the maximum number of lines that can be used to display various field types. If no
+ // value is specified for a particular type, we use the default value from {@link DataKind}.
+ protected static final int MAX_LINES_FOR_POSTAL_ADDRESS = 10;
+ protected static final int MAX_LINES_FOR_GROUP = 10;
+ protected static final int MAX_LINES_FOR_NOTE = 100;
+
private interface Tag {
static final String DATA_KIND = "DataKind";
static final String TYPE = "Type";
@@ -323,6 +329,8 @@
new EditField(StructuredPostal.FORMATTED_ADDRESS, R.string.postal_address,
FLAGS_POSTAL));
+ kind.maxLinesForDisplay = MAX_LINES_FOR_POSTAL_ADDRESS;
+
return kind;
}
@@ -391,6 +399,8 @@
kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
+ kind.maxLinesForDisplay = MAX_LINES_FOR_NOTE;
+
return kind;
}
@@ -430,6 +440,8 @@
kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(GroupMembership.GROUP_ROW_ID, -1, -1));
+ kind.maxLinesForDisplay = MAX_LINES_FOR_GROUP;
+
return kind;
}
@@ -1210,6 +1222,7 @@
R.string.postal_country, FLAGS_POSTAL).setOptional(true));
}
} else {
+ kind.maxLinesForDisplay= MAX_LINES_FOR_POSTAL_ADDRESS;
kind.fieldList.add(
new EditField(StructuredPostal.FORMATTED_ADDRESS, R.string.postal_address,
FLAGS_POSTAL));
@@ -1344,6 +1357,7 @@
new SimpleInflater(R.string.label_notes), new SimpleInflater(Note.NOTE));
kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
+ kind.maxLinesForDisplay = MAX_LINES_FOR_NOTE;
throwIfList(kind);
@@ -1417,6 +1431,7 @@
R.string.groupsLabel, Weight.GROUP_MEMBERSHIP, -1, null, null);
kind.fieldList.add(new EditField(GroupMembership.GROUP_ROW_ID, -1, -1));
+ kind.maxLinesForDisplay = MAX_LINES_FOR_GROUP;
throwIfList(kind);
diff --git a/src/com/android/contacts/model/DataKind.java b/src/com/android/contacts/model/DataKind.java
index 857f3e4..c697e6f 100644
--- a/src/com/android/contacts/model/DataKind.java
+++ b/src/com/android/contacts/model/DataKind.java
@@ -83,8 +83,16 @@
*/
public SimpleDateFormat dateFormatWithYear;
+ /**
+ * The number of lines available for displaying this kind of data in a
+ * {@link ContactDetailFragment} (and possibly elsewhere)
+ * Defaults to 1.
+ */
+ public int maxLinesForDisplay;
+
public DataKind() {
editorLayoutResourceId = R.layout.text_fields_editor_view;
+ maxLinesForDisplay = 1;
}
public DataKind(String mimeType, int titleRes, int weight, boolean editable,
@@ -95,6 +103,7 @@
this.editable = editable;
this.typeOverallMax = -1;
this.editorLayoutResourceId = editorLayoutResourceId;
+ maxLinesForDisplay = 1;
}
@Override
diff --git a/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java b/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
index 51c665f..67b7c0c 100644
--- a/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
+++ b/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
@@ -18,6 +18,7 @@
import com.android.contacts.ContactPhotoManager;
+import android.graphics.Bitmap;
import android.net.Uri;
import android.widget.ImageView;
@@ -56,6 +57,10 @@
}
@Override
+ public void cacheBitmap(Uri photoUri, Bitmap bitmap, byte[] photoBytes) {
+ }
+
+ @Override
public void preloadPhotosInBackground() {
}
}