1 package com.android.launcher3.folder;
3 import android.view.View;
5 import com.android.launcher3.config.FeatureFlags;
7 import java.util.ArrayList;
10 public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
12 static final int MAX_NUM_ITEMS_IN_PREVIEW = 4;
13 private static final int MIN_NUM_ITEMS_IN_PREVIEW = 2;
14 private static final int MAX_NUM_ITEMS_PER_ROW = 2;
16 final float MIN_SCALE = 0.48f;
17 final float MAX_SCALE = 0.58f;
18 final float MAX_RADIUS_DILATION = 0.15f;
19 final float ITEM_RADIUS_SCALE_FACTOR = 1.33f;
21 private float[] mTmpPoint = new float[2];
23 private float mAvailableSpace;
24 private float mRadius;
25 private float mIconSize;
26 private boolean mIsRtl;
27 private float mBaselineIconScale;
30 public void init(int availableSpace, int intrinsicIconSize, boolean rtl) {
31 mAvailableSpace = availableSpace;
32 mRadius = ITEM_RADIUS_SCALE_FACTOR * availableSpace / 2f;
33 mIconSize = intrinsicIconSize;
35 mBaselineIconScale = availableSpace / (intrinsicIconSize * 1f);
39 public FolderIcon.PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
40 int curNumItems, FolderIcon.PreviewItemDrawingParams params) {
42 float totalScale = scaleForItem(index, curNumItems);
45 float overlayAlpha = 0;
47 // Items beyond those displayed in the preview are animated to the center
48 if (index >= MAX_NUM_ITEMS_IN_PREVIEW) {
49 transX = transY = mAvailableSpace / 2 - (mIconSize * totalScale) / 2;
51 getPosition(index, curNumItems, mTmpPoint);
52 transX = mTmpPoint[0];
53 transY = mTmpPoint[1];
57 params = new FolderIcon.PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
59 params.update(transX, transY, totalScale);
60 params.overlayAlpha = overlayAlpha;
65 private void getPosition(int index, int curNumItems, float[] result) {
66 // The case of two items is homomorphic to the case of one.
67 curNumItems = Math.max(curNumItems, 2);
69 // We model the preview as a circle of items starting in the appropriate piece of the
70 // upper left quadrant (to achieve horizontal and vertical symmetry).
71 double theta0 = mIsRtl ? 0 : Math.PI;
73 // In RTL we go counterclockwise
74 int direction = mIsRtl ? 1 : -1;
76 double thetaShift = 0;
77 if (curNumItems == 3) {
78 thetaShift = Math.PI / 6;
79 } else if (curNumItems == 4) {
80 thetaShift = Math.PI / 4;
82 theta0 += direction * thetaShift;
84 // We want the items to appear in reading order. For the case of 1, 2 and 3 items, this
85 // is natural for the circular model. With 4 items, however, we need to swap the 3rd and
86 // 4th indices to achieve reading order.
87 if (curNumItems == 4 && index == 3) {
89 } else if (curNumItems == 4 && index == 2) {
93 // We bump the radius up between 0 and MAX_RADIUS_DILATION % as the number of items increase
94 float radius = mRadius * (1 + MAX_RADIUS_DILATION * (curNumItems -
95 MIN_NUM_ITEMS_IN_PREVIEW) / (MAX_NUM_ITEMS_IN_PREVIEW - MIN_NUM_ITEMS_IN_PREVIEW));
96 double theta = theta0 + index * (2 * Math.PI / curNumItems) * direction;
98 float halfIconSize = (mIconSize * scaleForItem(index, curNumItems)) / 2;
100 // Map the location along the circle, and offset the coordinates to represent the center
101 // of the icon, and to be based from the top / left of the preview area. The y component
102 // is inverted to match the coordinate system.
103 result[0] = mAvailableSpace / 2 + (float) (radius * Math.cos(theta) / 2) - halfIconSize;
104 result[1] = mAvailableSpace / 2 + (float) (- radius * Math.sin(theta) / 2) - halfIconSize;
109 public float scaleForItem(int index, int numItems) {
110 // Scale is determined by the number of items in the preview.
114 } else if (numItems == 3) {
115 scale = (MAX_SCALE + MIN_SCALE) / 2;
120 return scale * mBaselineIconScale;
124 public int maxNumItems() {
125 return MAX_NUM_ITEMS_IN_PREVIEW;
129 public boolean clipToBackground() {
134 public List<View> getItemsToDisplay(Folder folder) {
135 List<View> items = new ArrayList<>(folder.getItemsInReadingOrder());
136 int numItems = items.size();
137 if (FeatureFlags.LAUNCHER3_NEW_FOLDER_ANIMATION && numItems > MAX_NUM_ITEMS_IN_PREVIEW) {
138 // We match the icons in the preview with the layout of the opened folder (b/27944225),
139 // but we still need to figure out how we want to handle updating the preview when the
140 // upper left quadrant changes.
141 int appsPerRow = folder.mContent.getPageAt(0).getCountX();
142 int appsToDelete = appsPerRow - MAX_NUM_ITEMS_PER_ROW;
144 // We only display the upper left quadrant.
145 while (appsToDelete > 0) {
146 items.remove(MAX_NUM_ITEMS_PER_ROW);
150 return items.subList(0, Math.min(numItems, MAX_NUM_ITEMS_IN_PREVIEW));