blob: 00ff082855741ca278676ed65577af92be6a199b [file] [log] [blame]
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -08001/*
2 * Copyright (C) 2012 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
Mindy Pereira6f92de62011-12-19 11:31:48 -080017
Andy Huang30e2c242012-01-06 18:14:30 -080018package com.android.mail.browse;
Mindy Pereira6f92de62011-12-19 11:31:48 -080019
20import android.content.Context;
21import android.content.res.Resources;
22import android.text.TextPaint;
23import android.util.SparseArray;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.view.View.MeasureSpec;
27import android.view.ViewParent;
28import android.widget.TextView;
Andy Huang30e2c242012-01-06 18:14:30 -080029import com.android.mail.R;
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -080030import com.android.mail.ui.ViewMode;
Mindy Pereira6f92de62011-12-19 11:31:48 -080031
32/**
33 * Represents the coordinates of elements inside a CanvasConversationHeaderView
Mindy Pereira30fd47b2012-03-09 09:24:00 -080034 * (eg, checkmark, star, subject, sender, folders, etc.) It will inflate a view,
Mindy Pereira6f92de62011-12-19 11:31:48 -080035 * and record the coordinates of each element after layout. This will allows us
36 * to easily improve performance by creating custom view while still defining
37 * layout in XML files.
38 *
39 * @author phamm
40 */
Mindy Pereira0944e5e2012-01-03 11:14:58 -080041public class ConversationItemViewCoordinates {
Mindy Pereira6f92de62011-12-19 11:31:48 -080042 // Modes.
43 private static final int WIDE_MODE = 0;
44 private static final int NORMAL_MODE = 1;
45
46 // Static threshold.
Mindy Pereira30fd47b2012-03-09 09:24:00 -080047 private static int TOTAL_FOLDER_WIDTH = -1;
48 private static int TOTAL_FOLDER_WIDTH_WIDE = -1;
49 private static int FOLDER_CELL_WIDTH = -1;
Mindy Pereira6f92de62011-12-19 11:31:48 -080050 private static int sConversationHeights[];
51
52 // Checkmark.
53 int checkmarkX;
54 int checkmarkY;
55
56 // Star.
57 int starX;
58 int starY;
59
60 // Personal level.
61 int personalLevelX;
62 int personalLevelY;
63
64 // Senders.
65 int sendersX;
66 int sendersY;
67 int sendersWidth;
68 int sendersLineCount;
69 int sendersLineHeight;
70 int sendersFontSize;
71 int sendersAscent;
72
73 // Subject.
74 int subjectX;
75 int subjectY;
76 int subjectWidth;
77 int subjectLineCount;
78 int subjectFontSize;
79 int subjectAscent;
80
Mindy Pereira30fd47b2012-03-09 09:24:00 -080081 // Folders.
82 int foldersXEnd;
83 int foldersY;
84 int foldersHeight;
85 int foldersTopPadding;
86 int foldersFontSize;
87 int foldersAscent;
88 boolean showFolders;
Mindy Pereira6f92de62011-12-19 11:31:48 -080089
90 // Date.
91 int dateXEnd;
92 int dateY;
93 int dateFontSize;
94 int dateAscent;
95
96 // Paperclip.
97 int paperclipY;
98
Mindy Pereira30fd47b2012-03-09 09:24:00 -080099
Mindy Pereira6f92de62011-12-19 11:31:48 -0800100 // Cache to save Coordinates based on view width.
Mindy Pereira0944e5e2012-01-03 11:14:58 -0800101 private static SparseArray<ConversationItemViewCoordinates> mCache =
102 new SparseArray<ConversationItemViewCoordinates>();
Mindy Pereira6f92de62011-12-19 11:31:48 -0800103
104 private static TextPaint sPaint = new TextPaint();
105
106 static {
107 sPaint.setAntiAlias(true);
108 }
109
110 /**
111 * Returns whether to show a background on the attachment icon.
112 * Currently, we don't show a background in wide mode.
113 */
114 public static boolean showAttachmentBackground(int mode) {
115 return mode != WIDE_MODE;
116 }
117
118 /**
119 * Returns the mode of the header view (Wide/Normal/Narrow).
120 */
121 public static int getMode(Context context, ViewMode viewMode) {
122 Resources res = context.getResources();
Vikram Aggarwalfa131a22012-02-02 13:56:22 -0800123 return viewMode.getMode() == ViewMode.CONVERSATION_LIST ? res
Mindy Pereira6f92de62011-12-19 11:31:48 -0800124 .getInteger(R.integer.conversation_list_header_mode) : res
125 .getInteger(R.integer.conversation_header_mode);
126 }
127
128 /**
129 * Returns the layout id to be inflated in this mode.
130 */
131 private static int getLayoutId(int mode) {
132 switch (mode) {
133 case WIDE_MODE:
Mindy Pereira0944e5e2012-01-03 11:14:58 -0800134 return R.layout.conversation_item_view_wide;
Mindy Pereira6f92de62011-12-19 11:31:48 -0800135 case NORMAL_MODE:
Mindy Pereira0944e5e2012-01-03 11:14:58 -0800136 return R.layout.conversation_item_view_normal;
Mindy Pereira6f92de62011-12-19 11:31:48 -0800137 default:
138 throw new IllegalArgumentException("Unknown conversation header view mode " + mode);
139 }
140 }
141
142 /**
143 * Returns a value array multiplied by the specified density.
144 */
145 public static int[] getDensityDependentArray(int[] values, float density) {
146 int result[] = new int[values.length];
147 for (int i = 0; i < values.length; ++i) {
148 result[i] = (int) (values[i] * density);
149 }
150 return result;
151 }
152
153 /**
154 * Returns the height of the view in this mode.
155 */
156 public static int getHeight(Context context, int mode) {
157 Resources res = context.getResources();
158 float density = res.getDisplayMetrics().scaledDensity;
159 if (sConversationHeights == null) {
160 sConversationHeights = getDensityDependentArray(
161 res.getIntArray(R.array.conversation_heights), density);
162 }
163 return sConversationHeights[mode];
164 }
165
166 /**
167 * Refreshes the conversation heights array.
168 */
169 public static void refreshConversationHeights(Context context) {
170 Resources res = context.getResources();
171 float density = res.getDisplayMetrics().scaledDensity;
172 sConversationHeights = getDensityDependentArray(
173 res.getIntArray(R.array.conversation_heights), density);
174 }
175
176 /**
177 * Returns the x coordinates of a view by tracing up its hierarchy.
178 */
179 private static int getX(View view) {
180 int x = 0;
181 while (view != null) {
182 x += (int) view.getX();
183 ViewParent parent = view.getParent();
184 view = parent != null ? (View) parent : null;
185 }
186 return x;
187 }
188
189 /**
190 * Returns the y coordinates of a view by tracing up its hierarchy.
191 */
192 private static int getY(View view) {
193 int y = 0;
194 while (view != null) {
195 y += (int) view.getY();
196 ViewParent parent = view.getParent();
197 view = parent != null ? (View) parent : null;
198 }
199 return y;
200 }
201
202 /**
203 * Returns the number of lines of this text view.
204 */
205 private static int getLineCount(TextView textView) {
206 return Math.round(((float) textView.getHeight()) / textView.getLineHeight());
207 }
208
209 /**
210 * Returns the length (maximum of characters) of subject in this mode.
211 */
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800212 public static int getSubjectLength(Context context, int mode, boolean hasVisibleFolders,
Mindy Pereira6f92de62011-12-19 11:31:48 -0800213 boolean hasAttachments) {
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800214 if (hasVisibleFolders) {
Mindy Pereira6f92de62011-12-19 11:31:48 -0800215 if (hasAttachments) {
216 return context.getResources().getIntArray(
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800217 R.array.senders_with_folders_and_attachment_lengths)[mode];
Mindy Pereira6f92de62011-12-19 11:31:48 -0800218 } else {
219 return context.getResources().getIntArray(
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800220 R.array.senders_with_folders_lengths)[mode];
Mindy Pereira6f92de62011-12-19 11:31:48 -0800221 }
222 } else {
223 if (hasAttachments) {
224 return context.getResources().getIntArray(
225 R.array.senders_with_attachment_lengths)[mode];
226 } else {
227 return context.getResources().getIntArray(R.array.senders_lengths)[mode];
228 }
229 }
230 }
231
232 /**
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800233 * Returns the width available to draw folders in this mode.
Mindy Pereira6f92de62011-12-19 11:31:48 -0800234 */
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800235 public static int getFoldersWidth(Context context, int mode) {
Mindy Pereira6f92de62011-12-19 11:31:48 -0800236 Resources res = context.getResources();
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800237 if (TOTAL_FOLDER_WIDTH <= 0) {
238 TOTAL_FOLDER_WIDTH = res.getDimensionPixelSize(R.dimen.max_total_folder_width);
239 TOTAL_FOLDER_WIDTH_WIDE = res.getDimensionPixelSize(R.dimen.max_total_folder_width_wide);
Mindy Pereira6f92de62011-12-19 11:31:48 -0800240 }
241 switch (mode) {
242 case WIDE_MODE:
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800243 return TOTAL_FOLDER_WIDTH_WIDE;
Mindy Pereira6f92de62011-12-19 11:31:48 -0800244 case NORMAL_MODE:
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800245 return TOTAL_FOLDER_WIDTH;
Mindy Pereira6f92de62011-12-19 11:31:48 -0800246 default:
247 throw new IllegalArgumentException("Unknown conversation header view mode " + mode);
248 }
249 }
250
251 /**
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800252 * Returns the width of a cell to draw folders.
Mindy Pereira6f92de62011-12-19 11:31:48 -0800253 */
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800254 public static int getLabelCellWidth(Context context, int mode, int foldersCount) {
Mindy Pereira6f92de62011-12-19 11:31:48 -0800255 Resources res = context.getResources();
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800256 if (FOLDER_CELL_WIDTH <= 0) {
257 FOLDER_CELL_WIDTH = res.getDimensionPixelSize(R.dimen.folder_cell_width);
Mindy Pereira6f92de62011-12-19 11:31:48 -0800258 }
259 switch (mode) {
260 case WIDE_MODE:
261 case NORMAL_MODE:
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800262 return FOLDER_CELL_WIDTH;
Mindy Pereira6f92de62011-12-19 11:31:48 -0800263 default:
264 throw new IllegalArgumentException("Unknown conversation header view mode " + mode);
265 }
266 }
267
268 public static boolean displaySendersInline(int mode) {
269 switch (mode) {
270 case WIDE_MODE:
271 return false;
272 case NORMAL_MODE:
273 return true;
274 default:
275 throw new IllegalArgumentException("Unknown conversation header view mode " + mode);
276 }
277 }
278
279 /**
280 * Returns coordinates for elements inside a conversation header view given
281 * the view width.
282 */
Mindy Pereira0944e5e2012-01-03 11:14:58 -0800283 public static ConversationItemViewCoordinates forWidth(Context context, int width, int mode,
Mindy Pereira6f92de62011-12-19 11:31:48 -0800284 int standardScaledDimen) {
Mindy Pereira0944e5e2012-01-03 11:14:58 -0800285 ConversationItemViewCoordinates coordinates = mCache.get(width ^ standardScaledDimen);
Mindy Pereira6f92de62011-12-19 11:31:48 -0800286 if (coordinates == null) {
Mindy Pereira0944e5e2012-01-03 11:14:58 -0800287 coordinates = new ConversationItemViewCoordinates();
Mindy Pereira6f92de62011-12-19 11:31:48 -0800288 mCache.put(width ^ standardScaledDimen, coordinates);
289
290 // Layout the appropriate view.
291 int height = getHeight(context, mode);
292 View view = LayoutInflater.from(context).inflate(getLayoutId(mode), null);
293 int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
294 int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
295 view.measure(widthSpec, heightSpec);
296 view.layout(0, 0, width, height);
297
298 // Records coordinates.
299 View checkmark = view.findViewById(R.id.checkmark);
300 coordinates.checkmarkX = getX(checkmark);
301 coordinates.checkmarkY = getY(checkmark);
302
303 View star = view.findViewById(R.id.star);
304 coordinates.starX = getX(star);
305 coordinates.starY = getY(star);
306
307 View personalLevel = view.findViewById(R.id.personal_level);
308 coordinates.personalLevelX = getX(personalLevel);
309 coordinates.personalLevelY = getY(personalLevel);
310
311 TextView senders = (TextView) view.findViewById(R.id.senders);
312 coordinates.sendersX = getX(senders);
313 coordinates.sendersY = getY(senders);
314 coordinates.sendersWidth = senders.getWidth();
315 coordinates.sendersLineCount = getLineCount(senders);
316 coordinates.sendersLineHeight = senders.getLineHeight();
317 coordinates.sendersFontSize = (int) senders.getTextSize();
318 sPaint.setTextSize(coordinates.sendersFontSize);
319 coordinates.sendersAscent = (int) sPaint.ascent();
320
321 TextView subject = (TextView) view.findViewById(R.id.subject);
322 coordinates.subjectX = getX(subject);
323 coordinates.subjectY = getY(subject);
324 coordinates.subjectWidth = subject.getWidth();
325 coordinates.subjectLineCount = getLineCount(subject);
326 coordinates.subjectFontSize = (int) subject.getTextSize();
327 sPaint.setTextSize(coordinates.subjectFontSize);
328 coordinates.subjectAscent = (int) sPaint.ascent();
329
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800330 View folders = view.findViewById(R.id.folders);
331 if (folders != null) {
332 coordinates.showFolders = true;
333 coordinates.foldersXEnd = getX(folders) + folders.getWidth();
334 coordinates.foldersY = getY(folders);
335 coordinates.foldersHeight = folders.getHeight();
336 coordinates.foldersTopPadding = folders.getPaddingTop();
337 if (folders instanceof TextView) {
338 coordinates.foldersFontSize = (int) ((TextView) folders).getTextSize();
339 sPaint.setTextSize(coordinates.foldersFontSize);
340 coordinates.foldersAscent = (int) sPaint.ascent();
341 }
342 } else {
343 coordinates.showFolders = false;
Mindy Pereira6f92de62011-12-19 11:31:48 -0800344 }
345
346 TextView date = (TextView) view.findViewById(R.id.date);
347 coordinates.dateXEnd = getX(date) + date.getWidth();
348 coordinates.dateY = getY(date);
349 coordinates.dateFontSize = (int) date.getTextSize();
350 sPaint.setTextSize(coordinates.dateFontSize);
351 coordinates.dateAscent = (int) sPaint.ascent();
352
353 View paperclip = view.findViewById(R.id.paperclip);
354 coordinates.paperclipY = getY(paperclip);
355 }
356 return coordinates;
357 }
358
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800359 public static boolean displayFoldersAboveDate(boolean showFolders, int mode) {
360 return showFolders && mode == WIDE_MODE;
Mindy Pereira6f92de62011-12-19 11:31:48 -0800361 }
Mindy Pereirab5080d52012-03-09 11:26:44 -0800362
363 public static int getFolderCellWidth(Context context, int mode, int foldersCount) {
364 Resources res = context.getResources();
365 if (FOLDER_CELL_WIDTH <= 0) {
366 FOLDER_CELL_WIDTH = res.getDimensionPixelSize(R.dimen.folder_cell_width);
367 }
368 switch (mode) {
369 case WIDE_MODE:
370 case NORMAL_MODE:
371 return FOLDER_CELL_WIDTH;
372 default:
373 throw new IllegalArgumentException("Unknown conversation header view mode " + mode);
374 }
375 }
Mindy Pereira6f92de62011-12-19 11:31:48 -0800376}