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.graphics.RectF;
     20 import android.net.Uri;
     21 
     22 import com.android.messaging.util.Assert;
     23 import com.android.messaging.util.AvatarUriUtil;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Arrays;
     27 import java.util.List;
     28 
     29 public class AvatarGroupRequestDescriptor extends CompositeImageRequestDescriptor {
     30     private static final int MAX_GROUP_SIZE = 4;
     31 
     32     public AvatarGroupRequestDescriptor(final Uri uri, final int desiredWidth,
     33             final int desiredHeight) {
     34         this(convertToDescriptor(uri, desiredWidth, desiredHeight), desiredWidth, desiredHeight);
     35     }
     36 
     37     public AvatarGroupRequestDescriptor(final List<? extends ImageRequestDescriptor> descriptors,
     38             final int desiredWidth, final int desiredHeight) {
     39         super(descriptors, desiredWidth, desiredHeight);
     40         Assert.isTrue(descriptors.size() <= MAX_GROUP_SIZE);
     41     }
     42 
     43     private static List<? extends ImageRequestDescriptor> convertToDescriptor(final Uri uri,
     44             final int desiredWidth, final int desiredHeight) {
     45         final List<String> participantUriStrings = AvatarUriUtil.getGroupParticipantUris(uri);
     46         final List<AvatarRequestDescriptor> avatarDescriptors =
     47                 new ArrayList<AvatarRequestDescriptor>(participantUriStrings.size());
     48         for (final String uriString : participantUriStrings) {
     49             final AvatarRequestDescriptor descriptor = new AvatarRequestDescriptor(
     50                     Uri.parse(uriString), desiredWidth, desiredHeight);
     51             avatarDescriptors.add(descriptor);
     52         }
     53         return avatarDescriptors;
     54     }
     55 
     56     @Override
     57     public CompositeImageRequest<?> buildBatchImageRequest(final Context context) {
     58         return new CompositeImageRequest<AvatarGroupRequestDescriptor>(context, this);
     59     }
     60 
     61     @Override
     62     public List<RectF> getChildRequestTargetRects() {
     63         return Arrays.asList(generateDestRectArray());
     64     }
     65 
     66     /**
     67      * Generates an array of {@link RectF} which represents where each of the individual avatar
     68      * should be located in the final group avatar image. The location of each avatar depends on
     69      * the size of the group and the size of the overall group avatar size.
     70      */
     71     private RectF[] generateDestRectArray() {
     72         final int groupSize = mDescriptors.size();
     73         final float width = desiredWidth;
     74         final float height = desiredHeight;
     75         final float halfWidth = width / 2F;
     76         final float halfHeight = height / 2F;
     77         final RectF[] destArray = new RectF[groupSize];
     78         switch (groupSize) {
     79             case 2:
     80                 /**
     81                  * +-------+
     82                  * | 0 |   |
     83                  * +-------+
     84                  * |   | 1 |
     85                  * +-------+
     86                  *
     87                  * We want two circles which touches in the center. To get this we know that the
     88                  * diagonal of the overall group avatar is squareRoot(2) * w We also know that the
     89                  * two circles touches the at the center of the overall group avatar and the
     90                  * distance from the center of the circle to the corner of the group avatar is
     91                  * radius * squareRoot(2). Therefore, the following emerges.
     92                  *
     93                  * w * squareRoot(2) = 2 (radius + radius * squareRoot(2))
     94                  * Solving for radius we get:
     95                  * d = 2 * radius = ( squareRoot(2) / (squareRoot(2) + 1)) * w
     96                  * d = (2 - squareRoot(2)) * w
     97                  */
     98                 final float diameter = (float) ((2 - Math.sqrt(2)) * width);
     99                 destArray[0] = new RectF(0, 0, diameter, diameter);
    100                 destArray[1] = new RectF(width - diameter, height - diameter, width, height);
    101                 break;
    102             case 3:
    103                 /**
    104                  * +-------+
    105                  * | | 0 | |
    106                  * +-------+
    107                  * | 1 | 2 |
    108                  * +-------+
    109                  *   i0
    110                  *   |\
    111                  * a | \ c
    112                  *   --- i2
    113                  *    b
    114                  *
    115                  * a = radius * squareRoot(3) due to the triangle being a 30-60-90 right triangle.
    116                  * b = radius of circle
    117                  * c = 2 * radius of circle
    118                  *
    119                  * All three of the images are circles and therefore image zero will not touch
    120                  * image one or image two. Move image zero down so it touches image one and image
    121                  * two. This can be done by keeping image zero in the center and moving it down
    122                  * slightly. The amount to move down can be calculated by solving a right triangle.
    123                  * We know that the center x of image two to the center x of image zero is the
    124                  * radius of the circle, this is the length of edge b. Also we know that the
    125                  * distance from image zero to image two's center is 2 * radius, edge c. From this
    126                  * we know that the distance from center y of image two to center y of image one,
    127                  * edge a, is equal to radius * squareRoot(3) due to this triangle being a 30-60-90
    128                  * right triangle.
    129                  */
    130                 final float quarterWidth = width / 4F;
    131                 final float threeQuarterWidth = 3 * quarterWidth;
    132                 final float radius = height / 4F;
    133                 final float imageTwoCenterY = height - radius;
    134                 final float lengthOfEdgeA = (float) (radius * Math.sqrt(3));
    135                 final float imageZeroCenterY = imageTwoCenterY - lengthOfEdgeA;
    136                 final float imageZeroTop = imageZeroCenterY - radius;
    137                 final float imageZeroBottom = imageZeroCenterY + radius;
    138                 destArray[0] = new RectF(
    139                         quarterWidth, imageZeroTop, threeQuarterWidth, imageZeroBottom);
    140                 destArray[1] = new RectF(0, halfHeight, halfWidth, height);
    141                 destArray[2] = new RectF(halfWidth, halfHeight, width, height);
    142                 break;
    143             default:
    144                 /**
    145                  * +-------+
    146                  * | 0 | 1 |
    147                  * +-------+
    148                  * | 2 | 3 |
    149                  * +-------+
    150                  */
    151                 destArray[0] = new RectF(0, 0, halfWidth, halfHeight);
    152                 destArray[1] = new RectF(halfWidth, 0, width, halfHeight);
    153                 destArray[2] = new RectF(0, halfHeight, halfWidth, height);
    154                 destArray[3] = new RectF(halfWidth, halfHeight, width, height);
    155                 break;
    156         }
    157         return destArray;
    158     }
    159 }
    160