Loading res/values/colors.xml +2 −0 Original line number Diff line number Diff line Loading @@ -74,4 +74,6 @@ <!-- Color of the vertical stripe that goes on the left of a block quote inside a stream item --> <color name="stream_item_stripe_color">#CCCCCC</color> <!-- Color of image view placeholder. --> <color name="image_placeholder">#DDDDDD</color> </resources> src/com/android/contacts/ContactPhotoManager.java +77 −15 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; import android.os.Handler.Callback; Loading Loading @@ -67,6 +69,35 @@ public abstract class ContactPhotoManager { return R.drawable.ic_contact_picture_holo_light; } public static abstract class DefaultImageProvider { public abstract void applyDefaultImage(ImageView view, boolean hires, boolean darkTheme); } private static class AvatarDefaultImageProvider extends DefaultImageProvider { @Override public void applyDefaultImage(ImageView view, boolean hires, boolean darkTheme) { view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); } } private static class BlankDefaultImageProvider extends DefaultImageProvider { private static Drawable sDrawable; @Override public void applyDefaultImage(ImageView view, boolean hires, boolean darkTheme) { if (sDrawable == null) { Context context = view.getContext(); sDrawable = new ColorDrawable(context.getResources().getColor( R.color.image_placeholder)); } view.setImageDrawable(sDrawable); } } public static final DefaultImageProvider DEFAULT_AVATER = new AvatarDefaultImageProvider(); public static final DefaultImageProvider DEFAULT_BLANK = new BlankDefaultImageProvider(); /** * Requests the singleton instance of {@link AccountTypeManager} with data bound from * the available authenticators. This method can safely be called from the UI thread. Loading @@ -91,14 +122,32 @@ public abstract class ContactPhotoManager { * it is displayed immediately. Otherwise a request is sent to load the photo * from the database. */ public abstract void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme); public abstract void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider); /** * Calls {@link #loadPhoto(ImageView, long, boolean, boolean, DefaultImageProvider)} with * {@link #DEFAULT_AVATER}. */ public final void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme) { loadPhoto(view, photoId, hires, darkTheme, DEFAULT_AVATER); } /** * Load photo into the supplied image view. If the photo is already cached, * it is displayed immediately. Otherwise a request is sent to load the photo * from the location specified by the URI. */ public abstract void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme); public abstract void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider); /** * Calls {@link #loadPhoto(ImageView, Uri, boolean, boolean, DefaultImageProvider)} with * {@link #DEFAULT_AVATER}. */ public final void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme) { loadPhoto(view, photoUri, hires, darkTheme, DEFAULT_AVATER); } /** * Remove photo from the supplied image view. This also cancels current pending load request Loading Loading @@ -236,24 +285,28 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback { } @Override public void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme) { public void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { if (photoId == 0) { // No photo is needed view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); defaultProvider.applyDefaultImage(view, hires, darkTheme); mPendingRequests.remove(view); } else { loadPhotoByIdOrUri(view, Request.createFromId(photoId, hires, darkTheme)); loadPhotoByIdOrUri(view, Request.createFromId(photoId, hires, darkTheme, defaultProvider)); } } @Override public void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme) { public void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { if (photoUri == null) { // No photo is needed view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); defaultProvider.applyDefaultImage(view, hires, darkTheme); mPendingRequests.remove(view); } else { loadPhotoByIdOrUri(view, Request.createFromUri(photoUri, hires, darkTheme)); loadPhotoByIdOrUri(view, Request.createFromUri(photoUri, hires, darkTheme, defaultProvider)); } } Loading Loading @@ -292,12 +345,12 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback { BitmapHolder holder = mBitmapHolderCache.get(request.getKey()); if (holder == null) { // The bitmap has not been loaded - should display the placeholder image. view.setImageResource(getDefaultAvatarResId(request.isHires(), request.isDarkTheme())); request.applyDefaultImage(view); return false; } if (holder.bytes == null) { view.setImageResource(getDefaultAvatarResId(request.isHires(), request.isDarkTheme())); request.applyDefaultImage(view); return holder.fresh; } Loading Loading @@ -791,20 +844,25 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback { private final Uri mUri; private final boolean mDarkTheme; private final boolean mHires; private final DefaultImageProvider mDefaultProvider; private Request(long id, Uri uri, boolean hires, boolean darkTheme) { private Request(long id, Uri uri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { mId = id; mUri = uri; mDarkTheme = darkTheme; mHires = hires; mDefaultProvider = defaultProvider; } public static Request createFromId(long id, boolean hires, boolean darkTheme) { return new Request(id, null /* no URI */, hires, darkTheme); public static Request createFromId(long id, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { return new Request(id, null /* no URI */, hires, darkTheme, defaultProvider); } public static Request createFromUri(Uri uri, boolean hires, boolean darkTheme) { return new Request(0 /* no ID */, uri, hires, darkTheme); public static Request createFromUri(Uri uri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { return new Request(0 /* no ID */, uri, hires, darkTheme, defaultProvider); } public boolean isDarkTheme() { Loading Loading @@ -841,5 +899,9 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback { public Object getKey() { return mUri == null ? mId : mUri; } public void applyDefaultImage(ImageView view) { mDefaultProvider.applyDefaultImage(view, mHires, mDarkTheme); } } } src/com/android/contacts/detail/ContactDetailDisplayUtils.java +3 −2 Original line number Diff line number Diff line Loading @@ -249,7 +249,8 @@ public class ContactDetailDisplayUtils { setDataOrHideIfNone(snippet, statusView); if (photoUri != null) { ContactPhotoManager.getInstance(context).loadPhoto( statusPhotoView, Uri.parse(photoUri), true, false); statusPhotoView, Uri.parse(photoUri), true, false, ContactPhotoManager.DEFAULT_BLANK); statusPhotoView.setVisibility(View.VISIBLE); } else { statusPhotoView.setVisibility(View.GONE); Loading Loading @@ -339,7 +340,7 @@ public class ContactDetailDisplayUtils { pushLayerView.setEnabled(false); } contactPhotoManager.loadPhoto(imageView, Uri.parse(streamItemPhoto.getPhotoUri()), true, false); false, ContactPhotoManager.DEFAULT_BLANK); } @VisibleForTesting Loading tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java +6 −4 Original line number Diff line number Diff line Loading @@ -27,13 +27,15 @@ import android.widget.ImageView; */ public class MockContactPhotoManager extends ContactPhotoManager { @Override public void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme) { view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); public void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { defaultProvider.applyDefaultImage(view, hires, darkTheme); } @Override public void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme) { view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); public void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { defaultProvider.applyDefaultImage(view, hires, darkTheme); } @Override Loading Loading
res/values/colors.xml +2 −0 Original line number Diff line number Diff line Loading @@ -74,4 +74,6 @@ <!-- Color of the vertical stripe that goes on the left of a block quote inside a stream item --> <color name="stream_item_stripe_color">#CCCCCC</color> <!-- Color of image view placeholder. --> <color name="image_placeholder">#DDDDDD</color> </resources>
src/com/android/contacts/ContactPhotoManager.java +77 −15 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; import android.os.Handler.Callback; Loading Loading @@ -67,6 +69,35 @@ public abstract class ContactPhotoManager { return R.drawable.ic_contact_picture_holo_light; } public static abstract class DefaultImageProvider { public abstract void applyDefaultImage(ImageView view, boolean hires, boolean darkTheme); } private static class AvatarDefaultImageProvider extends DefaultImageProvider { @Override public void applyDefaultImage(ImageView view, boolean hires, boolean darkTheme) { view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); } } private static class BlankDefaultImageProvider extends DefaultImageProvider { private static Drawable sDrawable; @Override public void applyDefaultImage(ImageView view, boolean hires, boolean darkTheme) { if (sDrawable == null) { Context context = view.getContext(); sDrawable = new ColorDrawable(context.getResources().getColor( R.color.image_placeholder)); } view.setImageDrawable(sDrawable); } } public static final DefaultImageProvider DEFAULT_AVATER = new AvatarDefaultImageProvider(); public static final DefaultImageProvider DEFAULT_BLANK = new BlankDefaultImageProvider(); /** * Requests the singleton instance of {@link AccountTypeManager} with data bound from * the available authenticators. This method can safely be called from the UI thread. Loading @@ -91,14 +122,32 @@ public abstract class ContactPhotoManager { * it is displayed immediately. Otherwise a request is sent to load the photo * from the database. */ public abstract void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme); public abstract void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider); /** * Calls {@link #loadPhoto(ImageView, long, boolean, boolean, DefaultImageProvider)} with * {@link #DEFAULT_AVATER}. */ public final void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme) { loadPhoto(view, photoId, hires, darkTheme, DEFAULT_AVATER); } /** * Load photo into the supplied image view. If the photo is already cached, * it is displayed immediately. Otherwise a request is sent to load the photo * from the location specified by the URI. */ public abstract void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme); public abstract void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider); /** * Calls {@link #loadPhoto(ImageView, Uri, boolean, boolean, DefaultImageProvider)} with * {@link #DEFAULT_AVATER}. */ public final void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme) { loadPhoto(view, photoUri, hires, darkTheme, DEFAULT_AVATER); } /** * Remove photo from the supplied image view. This also cancels current pending load request Loading Loading @@ -236,24 +285,28 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback { } @Override public void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme) { public void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { if (photoId == 0) { // No photo is needed view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); defaultProvider.applyDefaultImage(view, hires, darkTheme); mPendingRequests.remove(view); } else { loadPhotoByIdOrUri(view, Request.createFromId(photoId, hires, darkTheme)); loadPhotoByIdOrUri(view, Request.createFromId(photoId, hires, darkTheme, defaultProvider)); } } @Override public void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme) { public void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { if (photoUri == null) { // No photo is needed view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); defaultProvider.applyDefaultImage(view, hires, darkTheme); mPendingRequests.remove(view); } else { loadPhotoByIdOrUri(view, Request.createFromUri(photoUri, hires, darkTheme)); loadPhotoByIdOrUri(view, Request.createFromUri(photoUri, hires, darkTheme, defaultProvider)); } } Loading Loading @@ -292,12 +345,12 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback { BitmapHolder holder = mBitmapHolderCache.get(request.getKey()); if (holder == null) { // The bitmap has not been loaded - should display the placeholder image. view.setImageResource(getDefaultAvatarResId(request.isHires(), request.isDarkTheme())); request.applyDefaultImage(view); return false; } if (holder.bytes == null) { view.setImageResource(getDefaultAvatarResId(request.isHires(), request.isDarkTheme())); request.applyDefaultImage(view); return holder.fresh; } Loading Loading @@ -791,20 +844,25 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback { private final Uri mUri; private final boolean mDarkTheme; private final boolean mHires; private final DefaultImageProvider mDefaultProvider; private Request(long id, Uri uri, boolean hires, boolean darkTheme) { private Request(long id, Uri uri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { mId = id; mUri = uri; mDarkTheme = darkTheme; mHires = hires; mDefaultProvider = defaultProvider; } public static Request createFromId(long id, boolean hires, boolean darkTheme) { return new Request(id, null /* no URI */, hires, darkTheme); public static Request createFromId(long id, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { return new Request(id, null /* no URI */, hires, darkTheme, defaultProvider); } public static Request createFromUri(Uri uri, boolean hires, boolean darkTheme) { return new Request(0 /* no ID */, uri, hires, darkTheme); public static Request createFromUri(Uri uri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { return new Request(0 /* no ID */, uri, hires, darkTheme, defaultProvider); } public boolean isDarkTheme() { Loading Loading @@ -841,5 +899,9 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback { public Object getKey() { return mUri == null ? mId : mUri; } public void applyDefaultImage(ImageView view) { mDefaultProvider.applyDefaultImage(view, mHires, mDarkTheme); } } }
src/com/android/contacts/detail/ContactDetailDisplayUtils.java +3 −2 Original line number Diff line number Diff line Loading @@ -249,7 +249,8 @@ public class ContactDetailDisplayUtils { setDataOrHideIfNone(snippet, statusView); if (photoUri != null) { ContactPhotoManager.getInstance(context).loadPhoto( statusPhotoView, Uri.parse(photoUri), true, false); statusPhotoView, Uri.parse(photoUri), true, false, ContactPhotoManager.DEFAULT_BLANK); statusPhotoView.setVisibility(View.VISIBLE); } else { statusPhotoView.setVisibility(View.GONE); Loading Loading @@ -339,7 +340,7 @@ public class ContactDetailDisplayUtils { pushLayerView.setEnabled(false); } contactPhotoManager.loadPhoto(imageView, Uri.parse(streamItemPhoto.getPhotoUri()), true, false); false, ContactPhotoManager.DEFAULT_BLANK); } @VisibleForTesting Loading
tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java +6 −4 Original line number Diff line number Diff line Loading @@ -27,13 +27,15 @@ import android.widget.ImageView; */ public class MockContactPhotoManager extends ContactPhotoManager { @Override public void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme) { view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); public void loadPhoto(ImageView view, long photoId, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { defaultProvider.applyDefaultImage(view, hires, darkTheme); } @Override public void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme) { view.setImageResource(getDefaultAvatarResId(hires, darkTheme)); public void loadPhoto(ImageView view, Uri photoUri, boolean hires, boolean darkTheme, DefaultImageProvider defaultProvider) { defaultProvider.applyDefaultImage(view, hires, darkTheme); } @Override Loading