1 /* 2 * Copyright (C) 2010 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 17 package com.android.gallery3d.common; 18 19 import android.content.Context; 20 import android.content.pm.PackageInfo; 21 import android.content.pm.PackageManager.NameNotFoundException; 22 import android.database.Cursor; 23 import android.os.Build; 24 import android.os.ParcelFileDescriptor; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import java.io.Closeable; 29 import java.io.IOException; 30 import java.io.InterruptedIOException; 31 32 public class Utils { 33 private static final String TAG = "Utils"; 34 private static final String DEBUG_TAG = "GalleryDebug"; 35 36 private static final long POLY64REV = 0x95AC9329AC4BC9B5L; 37 private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL; 38 39 private static long[] sCrcTable = new long[256]; 40 41 private static final boolean IS_DEBUG_BUILD = 42 Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug"); 43 44 private static final String MASK_STRING = "********************************"; 45 46 // Throws AssertionError if the input is false. 47 public static void assertTrue(boolean cond) { 48 if (!cond) { 49 throw new AssertionError(); 50 } 51 } 52 53 // Throws AssertionError with the message. We had a method having the form 54 // assertTrue(boolean cond, String message, Object ... args); 55 // However a call to that method will cause memory allocation even if the 56 // condition is false (due to autoboxing generated by "Object ... args"), 57 // so we don't use that anymore. 58 public static void fail(String message, Object ... args) { 59 throw new AssertionError( 60 args.length == 0 ? message : String.format(message, args)); 61 } 62 63 // Throws NullPointerException if the input is null. 64 public static <T> T checkNotNull(T object) { 65 if (object == null) throw new NullPointerException(); 66 return object; 67 } 68 69 // Returns true if two input Object are both null or equal 70 // to each other. 71 public static boolean equals(Object a, Object b) { 72 return (a == b) || (a == null ? false : a.equals(b)); 73 } 74 75 // Returns the next power of two. 76 // Returns the input if it is already power of 2. 77 // Throws IllegalArgumentException if the input is <= 0 or 78 // the answer overflows. 79 public static int nextPowerOf2(int n) { 80 if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n); 81 n -= 1; 82 n |= n >> 16; 83 n |= n >> 8; 84 n |= n >> 4; 85 n |= n >> 2; 86 n |= n >> 1; 87 return n + 1; 88 } 89 90 // Returns the previous power of two. 91 // Returns the input if it is already power of 2. 92 // Throws IllegalArgumentException if the input is <= 0 93 public static int prevPowerOf2(int n) { 94 if (n <= 0) throw new IllegalArgumentException(); 95 return Integer.highestOneBit(n); 96 } 97 98 // Returns the input value x clamped to the range [min, max]. 99 public static int clamp(int x, int min, int max) { 100 if (x > max) return max; 101 if (x < min) return min; 102 return x; 103 } 104 105 // Returns the input value x clamped to the range [min, max]. 106 public static float clamp(float x, float min, float max) { 107 if (x > max) return max; 108 if (x < min) return min; 109 return x; 110 } 111 112 // Returns the input value x clamped to the range [min, max]. 113 public static long clamp(long x, long min, long max) { 114 if (x > max) return max; 115 if (x < min) return min; 116 return x; 117 } 118 119 public static boolean isOpaque(int color) { 120 return color >>> 24 == 0xFF; 121 } 122 123 public static void swap(int[] array, int i, int j) { 124 int temp = array[i]; 125 array[i] = array[j]; 126 array[j] = temp; 127 } 128 129 /** 130 * A function thats returns a 64-bit crc for string 131 * 132 * @param in input string 133 * @return a 64-bit crc value 134 */ 135 public static final long crc64Long(String in) { 136 if (in == null || in.length() == 0) { 137 return 0; 138 } 139 return crc64Long(getBytes(in)); 140 } 141 142 static { 143 // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c 144 long part; 145 for (int i = 0; i < 256; i++) { 146 part = i; 147 for (int j = 0; j < 8; j++) { 148 long x = ((int) part & 1) != 0 ? POLY64REV : 0; 149 part = (part >> 1) ^ x; 150 } 151 sCrcTable[i] = part; 152 } 153 } 154 155 public static final long crc64Long(byte[] buffer) { 156 long crc = INITIALCRC; 157 for (int k = 0, n = buffer.length; k < n; ++k) { 158 crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8); 159 } 160 return crc; 161 } 162 163 public static byte[] getBytes(String in) { 164 byte[] result = new byte[in.length() * 2]; 165 int output = 0; 166 for (char ch : in.toCharArray()) { 167 result[output++] = (byte) (ch & 0xFF); 168 result[output++] = (byte) (ch >> 8); 169 } 170 return result; 171 } 172 173 public static void closeSilently(Closeable c) { 174 if (c == null) return; 175 try { 176 c.close(); 177 } catch (IOException t) { 178 Log.w(TAG, "close fail ", t); 179 } 180 } 181 182 public static int compare(long a, long b) { 183 return a < b ? -1 : a == b ? 0 : 1; 184 } 185 186 public static int ceilLog2(float value) { 187 int i; 188 for (i = 0; i < 31; i++) { 189 if ((1 << i) >= value) break; 190 } 191 return i; 192 } 193 194 public static int floorLog2(float value) { 195 int i; 196 for (i = 0; i < 31; i++) { 197 if ((1 << i) > value) break; 198 } 199 return i - 1; 200 } 201 202 public static void closeSilently(ParcelFileDescriptor fd) { 203 try { 204 if (fd != null) fd.close(); 205 } catch (Throwable t) { 206 Log.w(TAG, "fail to close", t); 207 } 208 } 209 210 public static void closeSilently(Cursor cursor) { 211 try { 212 if (cursor != null) cursor.close(); 213 } catch (Throwable t) { 214 Log.w(TAG, "fail to close", t); 215 } 216 } 217 218 public static float interpolateAngle( 219 float source, float target, float progress) { 220 // interpolate the angle from source to target 221 // We make the difference in the range of [-179, 180], this is the 222 // shortest path to change source to target. 223 float diff = target - source; 224 if (diff < 0) diff += 360f; 225 if (diff > 180) diff -= 360f; 226 227 float result = source + diff * progress; 228 return result < 0 ? result + 360f : result; 229 } 230 231 public static float interpolateScale( 232 float source, float target, float progress) { 233 return source + progress * (target - source); 234 } 235 236 public static String ensureNotNull(String value) { 237 return value == null ? "" : value; 238 } 239 240 public static float parseFloatSafely(String content, float defaultValue) { 241 if (content == null) return defaultValue; 242 try { 243 return Float.parseFloat(content); 244 } catch (NumberFormatException e) { 245 return defaultValue; 246 } 247 } 248 249 public static int parseIntSafely(String content, int defaultValue) { 250 if (content == null) return defaultValue; 251 try { 252 return Integer.parseInt(content); 253 } catch (NumberFormatException e) { 254 return defaultValue; 255 } 256 } 257 258 public static boolean isNullOrEmpty(String exifMake) { 259 return TextUtils.isEmpty(exifMake); 260 } 261 262 public static void waitWithoutInterrupt(Object object) { 263 try { 264 object.wait(); 265 } catch (InterruptedException e) { 266 Log.w(TAG, "unexpected interrupt: " + object); 267 } 268 } 269 270 public static boolean handleInterrruptedException(Throwable e) { 271 // A helper to deal with the interrupt exception 272 // If an interrupt detected, we will setup the bit again. 273 if (e instanceof InterruptedIOException 274 || e instanceof InterruptedException) { 275 Thread.currentThread().interrupt(); 276 return true; 277 } 278 return false; 279 } 280 281 /** 282 * @return String with special XML characters escaped. 283 */ 284 public static String escapeXml(String s) { 285 StringBuilder sb = new StringBuilder(); 286 for (int i = 0, len = s.length(); i < len; ++i) { 287 char c = s.charAt(i); 288 switch (c) { 289 case '<': sb.append("<"); break; 290 case '>': sb.append(">"); break; 291 case '\"': sb.append("""); break; 292 case '\'': sb.append("'"); break; 293 case '&': sb.append("&"); break; 294 default: sb.append(c); 295 } 296 } 297 return sb.toString(); 298 } 299 300 public static String getUserAgent(Context context) { 301 PackageInfo packageInfo; 302 try { 303 packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 304 } catch (NameNotFoundException e) { 305 throw new IllegalStateException("getPackageInfo failed"); 306 } 307 return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s", 308 packageInfo.packageName, 309 packageInfo.versionName, 310 Build.BRAND, 311 Build.DEVICE, 312 Build.MODEL, 313 Build.ID, 314 Build.VERSION.SDK_INT, 315 Build.VERSION.RELEASE, 316 Build.VERSION.INCREMENTAL); 317 } 318 319 public static String[] copyOf(String[] source, int newSize) { 320 String[] result = new String[newSize]; 321 newSize = Math.min(source.length, newSize); 322 System.arraycopy(source, 0, result, 0, newSize); 323 return result; 324 } 325 326 // Mask information for debugging only. It returns <code>info.toString()</code> directly 327 // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask ("****") 328 // in release build to protect the information (e.g. for privacy issue). 329 public static String maskDebugInfo(Object info) { 330 if (info == null) return null; 331 String s = info.toString(); 332 int length = Math.min(s.length(), MASK_STRING.length()); 333 return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length); 334 } 335 336 // This method should be ONLY used for debugging. 337 public static void debug(String message, Object ... args) { 338 Log.v(DEBUG_TAG, String.format(message, args)); 339 } 340 } 341