blob: 719b296c08229c9a7cdc2109a82eab469f44d8f6 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.datamodel.media;
import android.content.Context;
import android.graphics.RectF;
import android.net.Uri;
import com.android.messaging.util.Assert;
import com.android.messaging.util.AvatarUriUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AvatarGroupRequestDescriptor extends CompositeImageRequestDescriptor {
private static final int MAX_GROUP_SIZE = 4;
public AvatarGroupRequestDescriptor(final Uri uri, final int desiredWidth,
final int desiredHeight) {
this(convertToDescriptor(uri, desiredWidth, desiredHeight), desiredWidth, desiredHeight);
}
public AvatarGroupRequestDescriptor(final List<? extends ImageRequestDescriptor> descriptors,
final int desiredWidth, final int desiredHeight) {
super(descriptors, desiredWidth, desiredHeight);
Assert.isTrue(descriptors.size() <= MAX_GROUP_SIZE);
}
private static List<? extends ImageRequestDescriptor> convertToDescriptor(final Uri uri,
final int desiredWidth, final int desiredHeight) {
final List<String> participantUriStrings = AvatarUriUtil.getGroupParticipantUris(uri);
final List<AvatarRequestDescriptor> avatarDescriptors =
new ArrayList<AvatarRequestDescriptor>(participantUriStrings.size());
for (final String uriString : participantUriStrings) {
final AvatarRequestDescriptor descriptor = new AvatarRequestDescriptor(
Uri.parse(uriString), desiredWidth, desiredHeight);
avatarDescriptors.add(descriptor);
}
return avatarDescriptors;
}
@Override
public CompositeImageRequest<?> buildBatchImageRequest(final Context context) {
return new CompositeImageRequest<AvatarGroupRequestDescriptor>(context, this);
}
@Override
public List<RectF> getChildRequestTargetRects() {
return Arrays.asList(generateDestRectArray());
}
/**
* Generates an array of {@link RectF} which represents where each of the individual avatar
* should be located in the final group avatar image. The location of each avatar depends on
* the size of the group and the size of the overall group avatar size.
*/
private RectF[] generateDestRectArray() {
final int groupSize = mDescriptors.size();
final float width = desiredWidth;
final float height = desiredHeight;
final float halfWidth = width / 2F;
final float halfHeight = height / 2F;
final RectF[] destArray = new RectF[groupSize];
switch (groupSize) {
case 2:
/**
* +-------+
* | 0 | |
* +-------+
* | | 1 |
* +-------+
*
* We want two circles which touches in the center. To get this we know that the
* diagonal of the overall group avatar is squareRoot(2) * w We also know that the
* two circles touches the at the center of the overall group avatar and the
* distance from the center of the circle to the corner of the group avatar is
* radius * squareRoot(2). Therefore, the following emerges.
*
* w * squareRoot(2) = 2 (radius + radius * squareRoot(2))
* Solving for radius we get:
* d = 2 * radius = ( squareRoot(2) / (squareRoot(2) + 1)) * w
* d = (2 - squareRoot(2)) * w
*/
final float diameter = (float) ((2 - Math.sqrt(2)) * width);
destArray[0] = new RectF(0, 0, diameter, diameter);
destArray[1] = new RectF(width - diameter, height - diameter, width, height);
break;
case 3:
/**
* +-------+
* | | 0 | |
* +-------+
* | 1 | 2 |
* +-------+
* i0
* |\
* a | \ c
* --- i2
* b
*
* a = radius * squareRoot(3) due to the triangle being a 30-60-90 right triangle.
* b = radius of circle
* c = 2 * radius of circle
*
* All three of the images are circles and therefore image zero will not touch
* image one or image two. Move image zero down so it touches image one and image
* two. This can be done by keeping image zero in the center and moving it down
* slightly. The amount to move down can be calculated by solving a right triangle.
* We know that the center x of image two to the center x of image zero is the
* radius of the circle, this is the length of edge b. Also we know that the
* distance from image zero to image two's center is 2 * radius, edge c. From this
* we know that the distance from center y of image two to center y of image one,
* edge a, is equal to radius * squareRoot(3) due to this triangle being a 30-60-90
* right triangle.
*/
final float quarterWidth = width / 4F;
final float threeQuarterWidth = 3 * quarterWidth;
final float radius = height / 4F;
final float imageTwoCenterY = height - radius;
final float lengthOfEdgeA = (float) (radius * Math.sqrt(3));
final float imageZeroCenterY = imageTwoCenterY - lengthOfEdgeA;
final float imageZeroTop = imageZeroCenterY - radius;
final float imageZeroBottom = imageZeroCenterY + radius;
destArray[0] = new RectF(
quarterWidth, imageZeroTop, threeQuarterWidth, imageZeroBottom);
destArray[1] = new RectF(0, halfHeight, halfWidth, height);
destArray[2] = new RectF(halfWidth, halfHeight, width, height);
break;
default:
/**
* +-------+
* | 0 | 1 |
* +-------+
* | 2 | 3 |
* +-------+
*/
destArray[0] = new RectF(0, 0, halfWidth, halfHeight);
destArray[1] = new RectF(halfWidth, 0, width, halfHeight);
destArray[2] = new RectF(0, halfHeight, halfWidth, height);
destArray[3] = new RectF(halfWidth, halfHeight, width, height);
break;
}
return destArray;
}
}