DisplayUtils.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /* ownCloud Android client application
  2. *
  3. * @author Bartek Przybylski
  4. * @author David A. Velasco
  5. * Copyright (C) 2011 Bartek Przybylski
  6. * Copyright (C) 2012-2013 ownCloud Inc.
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. package com.owncloud.android.utils;
  22. import java.net.IDN;
  23. import java.text.DateFormat;
  24. import java.util.Arrays;
  25. import java.util.Calendar;
  26. import java.util.Date;
  27. import java.util.HashMap;
  28. import java.util.HashSet;
  29. import java.util.Set;
  30. import java.util.Vector;
  31. import android.annotation.TargetApi;
  32. import android.content.Context;
  33. import android.os.Build;
  34. import android.text.format.DateUtils;
  35. import android.webkit.MimeTypeMap;
  36. import com.owncloud.android.MainApp;
  37. import com.owncloud.android.R;
  38. import com.owncloud.android.datamodel.OCFile;
  39. /**
  40. * A helper class for some string operations.
  41. */
  42. public class DisplayUtils {
  43. private static final String OWNCLOUD_APP_NAME = "ownCloud";
  44. //private static String TAG = DisplayUtils.class.getSimpleName();
  45. private static final String[] sizeSuffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
  46. private static HashMap<String, String> mimeType2HUmanReadable;
  47. static {
  48. mimeType2HUmanReadable = new HashMap<String, String>();
  49. // images
  50. mimeType2HUmanReadable.put("image/jpeg", "JPEG image");
  51. mimeType2HUmanReadable.put("image/jpg", "JPEG image");
  52. mimeType2HUmanReadable.put("image/png", "PNG image");
  53. mimeType2HUmanReadable.put("image/bmp", "Bitmap image");
  54. mimeType2HUmanReadable.put("image/gif", "GIF image");
  55. mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");
  56. mimeType2HUmanReadable.put("image/tiff", "TIFF image");
  57. // music
  58. mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");
  59. mimeType2HUmanReadable.put("application/ogg", "OGG music file");
  60. }
  61. private static final String TYPE_APPLICATION = "application";
  62. private static final String TYPE_AUDIO = "audio";
  63. private static final String TYPE_IMAGE = "image";
  64. private static final String TYPE_TXT = "text";
  65. private static final String TYPE_VIDEO = "video";
  66. private static final String SUBTYPE_PDF = "pdf";
  67. private static final String SUBTYPE_XML = "xml";
  68. private static final String[] SUBTYPES_DOCUMENT = {
  69. "msword",
  70. "vnd.openxmlformats-officedocument.wordprocessingml.document",
  71. "vnd.oasis.opendocument.text",
  72. "rtf",
  73. "javascript"
  74. };
  75. private static Set<String> SUBTYPES_DOCUMENT_SET = new HashSet<String>(Arrays.asList(SUBTYPES_DOCUMENT));
  76. private static final String[] SUBTYPES_SPREADSHEET = {
  77. "msexcel",
  78. "vnd.ms-excel",
  79. "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  80. "vnd.oasis.opendocument.spreadsheet"
  81. };
  82. private static Set<String> SUBTYPES_SPREADSHEET_SET = new HashSet<String>(Arrays.asList(SUBTYPES_SPREADSHEET));
  83. private static final String[] SUBTYPES_PRESENTATION = {
  84. "mspowerpoint",
  85. "vnd.ms-powerpoint",
  86. "vnd.openxmlformats-officedocument.presentationml.presentation",
  87. "vnd.oasis.opendocument.presentation"
  88. };
  89. private static Set<String> SUBTYPES_PRESENTATION_SET = new HashSet<String>(Arrays.asList(SUBTYPES_PRESENTATION));
  90. private static final String[] SUBTYPES_COMPRESSED = {"x-tar", "x-gzip", "zip"};
  91. private static final Set<String> SUBTYPES_COMPRESSED_SET = new HashSet<String>(Arrays.asList(SUBTYPES_COMPRESSED));
  92. private static final String SUBTYPE_OCTET_STREAM = "octet-stream";
  93. private static final String EXTENSION_RAR = "rar";
  94. private static final String EXTENSION_RTF = "rtf";
  95. private static final String EXTENSION_3GP = "3gp";
  96. private static final String EXTENSION_PY = "py";
  97. private static final String EXTENSION_JS = "js";
  98. /**
  99. * Converts the file size in bytes to human readable output.
  100. *
  101. * @param bytes Input file size
  102. * @return Like something readable like "12 MB"
  103. */
  104. public static String bytesToHumanReadable(long bytes) {
  105. double result = bytes;
  106. int attachedsuff = 0;
  107. while (result > 1024 && attachedsuff < sizeSuffixes.length) {
  108. result /= 1024.;
  109. attachedsuff++;
  110. }
  111. result = ((int) (result * 100)) / 100.;
  112. return result + " " + sizeSuffixes[attachedsuff];
  113. }
  114. /**
  115. * Converts MIME types like "image/jpg" to more end user friendly output
  116. * like "JPG image".
  117. *
  118. * @param mimetype MIME type to convert
  119. * @return A human friendly version of the MIME type
  120. */
  121. public static String convertMIMEtoPrettyPrint(String mimetype) {
  122. if (mimeType2HUmanReadable.containsKey(mimetype)) {
  123. return mimeType2HUmanReadable.get(mimetype);
  124. }
  125. if (mimetype.split("/").length >= 2)
  126. return mimetype.split("/")[1].toUpperCase() + " file";
  127. return "Unknown type";
  128. }
  129. /**
  130. * Returns the resource identifier of an image to use as icon associated to a known MIME type.
  131. *
  132. * @param mimetype MIME type string; if NULL, the method tries to guess it from the extension in filename
  133. * @param filename Name, with extension.
  134. * @return Identifier of an image resource.
  135. */
  136. public static int getFileTypeIconId(String mimetype, String filename) {
  137. if (mimetype == null) {
  138. String fileExtension = getExtension(filename);
  139. mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
  140. if (mimetype == null) {
  141. mimetype = TYPE_APPLICATION + "/" + SUBTYPE_OCTET_STREAM;
  142. }
  143. }
  144. if ("DIR".equals(mimetype)) {
  145. return R.drawable.ic_menu_archive;
  146. } else {
  147. String [] parts = mimetype.split("/");
  148. String type = parts[0];
  149. String subtype = (parts.length > 1) ? parts[1] : "";
  150. if(TYPE_TXT.equals(type)) {
  151. return R.drawable.file_doc;
  152. } else if(TYPE_IMAGE.equals(type)) {
  153. return R.drawable.file_image;
  154. } else if(TYPE_VIDEO.equals(type)) {
  155. return R.drawable.file_movie;
  156. } else if(TYPE_AUDIO.equals(type)) {
  157. return R.drawable.file_sound;
  158. } else if(TYPE_APPLICATION.equals(type)) {
  159. if (SUBTYPE_PDF.equals(subtype)) {
  160. return R.drawable.file_pdf;
  161. } else if (SUBTYPE_XML.equals(subtype)) {
  162. return R.drawable.file_doc;
  163. } else if (SUBTYPES_DOCUMENT_SET.contains(subtype)) {
  164. return R.drawable.file_doc;
  165. } else if (SUBTYPES_SPREADSHEET_SET.contains(subtype)) {
  166. return R.drawable.file_xls;
  167. } else if (SUBTYPES_PRESENTATION_SET.contains(subtype)) {
  168. return R.drawable.file_ppt;
  169. } else if (SUBTYPES_COMPRESSED_SET.contains(subtype)) {
  170. return R.drawable.file_zip;
  171. } else if (SUBTYPE_OCTET_STREAM.equals(subtype) ) {
  172. if (getExtension(filename).equalsIgnoreCase(EXTENSION_RAR)) {
  173. return R.drawable.file_zip;
  174. } else if (getExtension(filename).equalsIgnoreCase(EXTENSION_RTF)) {
  175. return R.drawable.file_doc;
  176. } else if (getExtension(filename).equalsIgnoreCase(EXTENSION_3GP)) {
  177. return R.drawable.file_movie;
  178. } else if ( getExtension(filename).equalsIgnoreCase(EXTENSION_PY) ||
  179. getExtension(filename).equalsIgnoreCase(EXTENSION_JS)) {
  180. return R.drawable.file_doc;
  181. }
  182. }
  183. }
  184. }
  185. // default icon
  186. return R.drawable.file;
  187. }
  188. private static String getExtension(String filename) {
  189. String extension = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
  190. return extension;
  191. }
  192. /**
  193. * Converts Unix time to human readable format
  194. * @param milliseconds that have passed since 01/01/1970
  195. * @return The human readable time for the users locale
  196. */
  197. public static String unixTimeToHumanReadable(long milliseconds) {
  198. Date date = new Date(milliseconds);
  199. DateFormat df = DateFormat.getDateTimeInstance();
  200. return df.format(date);
  201. }
  202. public static int getSeasonalIconId() {
  203. if (Calendar.getInstance().get(Calendar.DAY_OF_YEAR) >= 354 &&
  204. MainApp.getAppContext().getString(R.string.app_name).equals(OWNCLOUD_APP_NAME)) {
  205. return R.drawable.winter_holidays_icon;
  206. } else {
  207. return R.drawable.icon;
  208. }
  209. }
  210. /**
  211. * Converts an internationalized domain name (IDN) in an URL to and from ASCII/Unicode.
  212. * @param url the URL where the domain name should be converted
  213. * @param toASCII if true converts from Unicode to ASCII, if false converts from ASCII to Unicode
  214. * @return the URL containing the converted domain name
  215. */
  216. @TargetApi(Build.VERSION_CODES.GINGERBREAD)
  217. public static String convertIdn(String url, boolean toASCII) {
  218. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
  219. // Find host name after '//' or '@'
  220. int hostStart = 0;
  221. if (url.indexOf("//") != -1) {
  222. hostStart = url.indexOf("//") + "//".length();
  223. } else if (url.indexOf("@") != -1) {
  224. hostStart = url.indexOf("@") + "@".length();
  225. }
  226. int hostEnd = url.substring(hostStart).indexOf("/");
  227. // Handle URL which doesn't have a path (path is implicitly '/')
  228. hostEnd = (hostEnd == -1 ? url.length() : hostStart + hostEnd);
  229. String host = url.substring(hostStart, hostEnd);
  230. host = (toASCII ? IDN.toASCII(host) : IDN.toUnicode(host));
  231. return url.substring(0, hostStart) + host + url.substring(hostEnd);
  232. } else {
  233. return url;
  234. }
  235. }
  236. /**
  237. * Get the file extension if it is on path as type "content://.../DocInfo.doc"
  238. * @param filepath: Content Uri converted to string format
  239. * @return String: fileExtension (type '.pdf'). Empty if no extension
  240. */
  241. public static String getComposedFileExtension(String filepath) {
  242. String fileExtension = "";
  243. String fileNameInContentUri = filepath.substring(filepath.lastIndexOf("/"));
  244. // Check if extension is included in uri
  245. int pos = fileNameInContentUri.lastIndexOf('.');
  246. if (pos >= 0) {
  247. fileExtension = fileNameInContentUri.substring(pos);
  248. }
  249. return fileExtension;
  250. }
  251. @SuppressWarnings("deprecation")
  252. public static CharSequence getRelativeDateTimeString (
  253. Context c, long time, long minResolution, long transitionResolution, int flags
  254. ){
  255. CharSequence dateString = "";
  256. // in Future
  257. if (time > System.currentTimeMillis()){
  258. return DisplayUtils.unixTimeToHumanReadable(time);
  259. }
  260. // < 60 seconds -> seconds ago
  261. else if ((System.currentTimeMillis() - time) < 60 * 1000) {
  262. return c.getString(R.string.file_list_seconds_ago);
  263. } else {
  264. // Workaround 2.x bug (see https://github.com/owncloud/android/issues/716)
  265. if ( Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB &&
  266. (System.currentTimeMillis() - time) > 24 * 60 * 60 * 1000 ) {
  267. Date date = new Date(time);
  268. date.setHours(0);
  269. date.setMinutes(0);
  270. date.setSeconds(0);
  271. dateString = DateUtils.getRelativeDateTimeString(
  272. c, date.getTime(), minResolution, transitionResolution, flags
  273. );
  274. } else {
  275. dateString = DateUtils.getRelativeDateTimeString(c, time, minResolution, transitionResolution, flags);
  276. }
  277. }
  278. return dateString.toString().split(",")[0];
  279. }
  280. /**
  281. * Update the passed path removing the last "/" if it is not the root folder
  282. * @param path
  283. */
  284. public static String getPathWithoutLastSlash(String path) {
  285. // Remove last slash from path
  286. if (path.length() > 1 && path.charAt(path.length()-1) == OCFile.PATH_SEPARATOR.charAt(0)) {
  287. path = path.substring(0, path.length()-1);
  288. }
  289. return path;
  290. }
  291. }