Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.messaging.datamodel.media;
     17 
     18 import android.content.Context;
     19 import android.content.res.Resources;
     20 import android.graphics.Bitmap;
     21 import android.graphics.Canvas;
     22 import android.graphics.Matrix;
     23 import android.graphics.Paint;
     24 import android.graphics.Rect;
     25 import android.graphics.RectF;
     26 import android.graphics.Typeface;
     27 import android.graphics.drawable.BitmapDrawable;
     28 import android.media.ExifInterface;
     29 import android.net.Uri;
     30 
     31 import com.android.messaging.R;
     32 import com.android.messaging.util.Assert;
     33 import com.android.messaging.util.AvatarUriUtil;
     34 import com.android.messaging.util.LogUtil;
     35 import com.android.messaging.util.UriUtil;
     36 
     37 import java.io.FileNotFoundException;
     38 import java.io.IOException;
     39 import java.io.InputStream;
     40 import java.util.List;
     41 
     42 public class AvatarRequest extends UriImageRequest<AvatarRequestDescriptor> {
     43     private static Bitmap sDefaultPersonBitmap;
     44     private static Bitmap sDefaultPersonBitmapLarge;
     45 
     46     public AvatarRequest(final Context context,
     47             final AvatarRequestDescriptor descriptor) {
     48         super(context, descriptor);
     49     }
     50 
     51     @Override
     52     protected InputStream getInputStreamForResource() throws FileNotFoundException {
     53         if (UriUtil.isLocalResourceUri(mDescriptor.uri)) {
     54             return super.getInputStreamForResource();
     55         } else {
     56             final Uri primaryUri = AvatarUriUtil.getPrimaryUri(mDescriptor.uri);
     57             Assert.isTrue(UriUtil.isLocalResourceUri(primaryUri));
     58             return mContext.getContentResolver().openInputStream(primaryUri);
     59         }
     60     }
     61 
     62     /**
     63      * We can load multiple types of images for avatars depending on the uri. The uri should be
     64      * built by {@link com.android.messaging.util.AvatarUriUtil} which will decide on
     65      * what uri to build based on the available profile photo and name. Here we will check if the
     66      * image is a local resource (ie profile photo uri), if the resource isn't a local one we will
     67      * generate a tile with the first letter of the name.
     68      */
     69     @Override
     70     protected ImageResource loadMediaInternal(List<MediaRequest<ImageResource>> chainedTasks)
     71             throws IOException {
     72         Assert.isNotMainThread();
     73         String avatarType = AvatarUriUtil.getAvatarType(mDescriptor.uri);
     74         Bitmap bitmap = null;
     75         int orientation = ExifInterface.ORIENTATION_NORMAL;
     76         final boolean isLocalResourceUri = UriUtil.isLocalResourceUri(mDescriptor.uri) ||
     77                 AvatarUriUtil.TYPE_LOCAL_RESOURCE_URI.equals(avatarType);
     78         if (isLocalResourceUri) {
     79             try {
     80                 ImageResource imageResource = super.loadMediaInternal(chainedTasks);
     81                 bitmap = imageResource.getBitmap();
     82                 orientation = imageResource.mOrientation;
     83             } catch (Exception ex) {
     84                 // If we encountered any exceptions trying to load the local avatar resource,
     85                 // fall back to generated avatar.
     86                 LogUtil.w(LogUtil.BUGLE_IMAGE_TAG, "AvatarRequest: failed to load local avatar " +
     87                         "resource, switching to fallback rendering", ex);
     88             }
     89         }
     90 
     91         final int width = mDescriptor.desiredWidth;
     92         final int height = mDescriptor.desiredHeight;
     93         // Check to see if we already got the bitmap. If not get a fallback avatar
     94         if (bitmap == null) {
     95             Uri generatedUri = mDescriptor.uri;
     96             if (isLocalResourceUri) {
     97                 // If we are here, we just failed to load the local resource. Use the fallback Uri
     98                 // if possible.
     99                 generatedUri = AvatarUriUtil.getFallbackUri(mDescriptor.uri);
    100                 if (generatedUri == null) {
    101                     // No fallback Uri was provided, use the default avatar.
    102                     generatedUri = AvatarUriUtil.DEFAULT_BACKGROUND_AVATAR;
    103                 }
    104             }
    105 
    106             avatarType = AvatarUriUtil.getAvatarType(generatedUri);
    107             if (AvatarUriUtil.TYPE_LETTER_TILE_URI.equals(avatarType)) {
    108                 final String name = AvatarUriUtil.getName(generatedUri);
    109                 bitmap = renderLetterTile(name, width, height);
    110             } else {
    111                 bitmap = renderDefaultAvatar(width, height);
    112             }
    113         }
    114         return new DecodedImageResource(getKey(), bitmap, orientation);
    115     }
    116 
    117     private Bitmap renderDefaultAvatar(final int width, final int height) {
    118         final Bitmap bitmap = getBitmapPool().createOrReuseBitmap(width, height,
    119                 getBackgroundColor());
    120         final Canvas canvas = new Canvas(bitmap);
    121 
    122         if (sDefaultPersonBitmap == null) {
    123             final BitmapDrawable defaultPerson = (BitmapDrawable) mContext.getResources()
    124                     .getDrawable(R.drawable.ic_person_light);
    125             sDefaultPersonBitmap = defaultPerson.getBitmap();
    126         }
    127         if (sDefaultPersonBitmapLarge == null) {
    128             final BitmapDrawable largeDefaultPerson = (BitmapDrawable) mContext.getResources()
    129                     .getDrawable(R.drawable.ic_person_light_large);
    130             sDefaultPersonBitmapLarge = largeDefaultPerson.getBitmap();
    131         }
    132 
    133         Bitmap defaultPerson = null;
    134         if (mDescriptor.isWearBackground) {
    135             final BitmapDrawable wearDefaultPerson = (BitmapDrawable) mContext.getResources()
    136                     .getDrawable(R.drawable.ic_person_wear);
    137             defaultPerson = wearDefaultPerson.getBitmap();
    138         } else {
    139             final boolean isLargeDefault = (width > sDefaultPersonBitmap.getWidth()) ||
    140                     (height > sDefaultPersonBitmap.getHeight());
    141             defaultPerson =
    142                     isLargeDefault ? sDefaultPersonBitmapLarge : sDefaultPersonBitmap;
    143         }
    144 
    145         final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    146         final Matrix matrix = new Matrix();
    147         final RectF source = new RectF(0, 0, defaultPerson.getWidth(), defaultPerson.getHeight());
    148         final RectF dest = new RectF(0, 0, width, height);
    149         matrix.setRectToRect(source, dest, Matrix.ScaleToFit.FILL);
    150 
    151         canvas.drawBitmap(defaultPerson, matrix, paint);
    152 
    153         return bitmap;
    154     }
    155 
    156     private Bitmap renderLetterTile(final String name, final int width, final int height) {
    157         final float halfWidth = width / 2;
    158         final float halfHeight = height / 2;
    159         final int minOfWidthAndHeight = Math.min(width, height);
    160         final Bitmap bitmap = getBitmapPool().createOrReuseBitmap(width, height,
    161                 getBackgroundColor());
    162         final Resources resources = mContext.getResources();
    163         final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    164         paint.setTypeface(Typeface.create("sans-serif-thin", Typeface.NORMAL));
    165         paint.setColor(resources.getColor(R.color.letter_tile_font_color));
    166         final float letterToTileRatio = resources.getFraction(R.dimen.letter_to_tile_ratio, 1, 1);
    167         paint.setTextSize(letterToTileRatio * minOfWidthAndHeight);
    168 
    169         final String firstCharString = name.substring(0, 1).toUpperCase();
    170         final Rect textBound = new Rect();
    171         paint.getTextBounds(firstCharString, 0, 1, textBound);
    172 
    173         final Canvas canvas = new Canvas(bitmap);
    174         final float xOffset = halfWidth - textBound.centerX();
    175         final float yOffset = halfHeight - textBound.centerY();
    176         canvas.drawText(firstCharString, xOffset, yOffset, paint);
    177 
    178         return bitmap;
    179     }
    180 
    181     private int getBackgroundColor() {
    182         return mContext.getResources().getColor(R.color.primary_color);
    183     }
    184 
    185     @Override
    186     public int getCacheId() {
    187         return BugleMediaCacheManager.AVATAR_IMAGE_CACHE;
    188     }
    189 }
    190