• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.PendingIntent;
20 import android.content.Context;
21 import android.content.pm.PackageInfo;
22 import android.content.pm.PackageManager.NameNotFoundException;
23 import android.database.Cursor;
24 import android.os.Build;
25 import android.os.Environment;
26 import android.os.Parcel;
27 import android.os.ParcelFileDescriptor;
28 import android.os.StatFs;
29 import android.text.TextUtils;
30 import android.util.Log;
31 
32 import java.io.Closeable;
33 import java.io.InterruptedIOException;
34 import java.util.Random;
35 
36 public class Utils {
37     private static final String TAG = "Utils";
38     private static final String DEBUG_TAG = "GalleryDebug";
39 
40     private static final long POLY64REV = 0x95AC9329AC4BC9B5L;
41     private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;
42 
43     private static long[] sCrcTable = new long[256];
44 
45     private static final boolean IS_DEBUG_BUILD =
46             Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug");
47 
48     private static final String MASK_STRING = "********************************";
49 
50     // Throws AssertionError if the input is false.
assertTrue(boolean cond)51     public static void assertTrue(boolean cond) {
52         if (!cond) {
53             throw new AssertionError();
54         }
55     }
56 
57     // Throws AssertionError if the input is false.
assertTrue(boolean cond, String message, Object ... args)58     public static void assertTrue(boolean cond, String message, Object ... args) {
59         if (!cond) {
60             throw new AssertionError(
61                     args.length == 0 ? message : String.format(message, args));
62         }
63     }
64 
65     // Throws NullPointerException if the input is null.
checkNotNull(T object)66     public static <T> T checkNotNull(T object) {
67         if (object == null) throw new NullPointerException();
68         return object;
69     }
70 
71     // Returns true if two input Object are both null or equal
72     // to each other.
equals(Object a, Object b)73     public static boolean equals(Object a, Object b) {
74         return (a == b) || (a == null ? false : a.equals(b));
75     }
76 
77     // Returns true if the input is power of 2.
78     // Throws IllegalArgumentException if the input is <= 0.
isPowerOf2(int n)79     public static boolean isPowerOf2(int n) {
80         if (n <= 0) throw new IllegalArgumentException();
81         return (n & -n) == n;
82     }
83 
84     // Returns the next power of two.
85     // Returns the input if it is already power of 2.
86     // Throws IllegalArgumentException if the input is <= 0 or
87     // the answer overflows.
nextPowerOf2(int n)88     public static int nextPowerOf2(int n) {
89         if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException();
90         n -= 1;
91         n |= n >> 16;
92         n |= n >> 8;
93         n |= n >> 4;
94         n |= n >> 2;
95         n |= n >> 1;
96         return n + 1;
97     }
98 
99     // Returns the previous power of two.
100     // Returns the input if it is already power of 2.
101     // Throws IllegalArgumentException if the input is <= 0
prevPowerOf2(int n)102     public static int prevPowerOf2(int n) {
103         if (n <= 0) throw new IllegalArgumentException();
104         return Integer.highestOneBit(n);
105     }
106 
107     // Returns the euclidean distance between (x, y) and (sx, sy).
distance(float x, float y, float sx, float sy)108     public static float distance(float x, float y, float sx, float sy) {
109         float dx = x - sx;
110         float dy = y - sy;
111         return (float) Math.hypot(dx, dy);
112     }
113 
114     // Returns the input value x clamped to the range [min, max].
clamp(int x, int min, int max)115     public static int clamp(int x, int min, int max) {
116         if (x > max) return max;
117         if (x < min) return min;
118         return x;
119     }
120 
121     // Returns the input value x clamped to the range [min, max].
clamp(float x, float min, float max)122     public static float clamp(float x, float min, float max) {
123         if (x > max) return max;
124         if (x < min) return min;
125         return x;
126     }
127 
128     // Returns the input value x clamped to the range [min, max].
clamp(long x, long min, long max)129     public static long clamp(long x, long min, long max) {
130         if (x > max) return max;
131         if (x < min) return min;
132         return x;
133     }
134 
isOpaque(int color)135     public static boolean isOpaque(int color) {
136         return color >>> 24 == 0xFF;
137     }
138 
swap(T[] array, int i, int j)139     public static <T> void swap(T[] array, int i, int j) {
140         T temp = array[i];
141         array[i] = array[j];
142         array[j] = temp;
143     }
144 
swap(int[] array, int i, int j)145     public static void swap(int[] array, int i, int j) {
146         int temp = array[i];
147         array[i] = array[j];
148         array[j] = temp;
149     }
150 
151     /**
152      * A function thats returns a 64-bit crc for string
153      *
154      * @param in input string
155      * @return a 64-bit crc value
156      */
crc64Long(String in)157     public static final long crc64Long(String in) {
158         if (in == null || in.length() == 0) {
159             return 0;
160         }
161         return crc64Long(getBytes(in));
162     }
163 
164     static {
165         // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c
166         long part;
167         for (int i = 0; i < 256; i++) {
168             part = i;
169             for (int j = 0; j < 8; j++) {
170                 long x = ((int) part & 1) != 0 ? POLY64REV : 0;
171                 part = (part >> 1) ^ x;
172             }
173             sCrcTable[i] = part;
174         }
175     }
176 
crc64Long(byte[] buffer)177     public static final long crc64Long(byte[] buffer) {
178         long crc = INITIALCRC;
179         for (int k = 0, n = buffer.length; k < n; ++k) {
180             crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8);
181         }
182         return crc;
183     }
184 
getBytes(String in)185     public static byte[] getBytes(String in) {
186         byte[] result = new byte[in.length() * 2];
187         int output = 0;
188         for (char ch : in.toCharArray()) {
189             result[output++] = (byte) (ch & 0xFF);
190             result[output++] = (byte) (ch >> 8);
191         }
192         return result;
193     }
194 
closeSilently(Closeable c)195     public static void closeSilently(Closeable c) {
196         if (c == null) return;
197         try {
198             c.close();
199         } catch (Throwable t) {
200             Log.w(TAG, "close fail", t);
201         }
202     }
203 
compare(long a, long b)204     public static int compare(long a, long b) {
205         return a < b ? -1 : a == b ? 0 : 1;
206     }
207 
ceilLog2(float value)208     public static int ceilLog2(float value) {
209         int i;
210         for (i = 0; i < 31; i++) {
211             if ((1 << i) >= value) break;
212         }
213         return i;
214     }
215 
floorLog2(float value)216     public static int floorLog2(float value) {
217         int i;
218         for (i = 0; i < 31; i++) {
219             if ((1 << i) > value) break;
220         }
221         return i - 1;
222     }
223 
closeSilently(ParcelFileDescriptor fd)224     public static void closeSilently(ParcelFileDescriptor fd) {
225         try {
226             if (fd != null) fd.close();
227         } catch (Throwable t) {
228             Log.w(TAG, "fail to close", t);
229         }
230     }
231 
closeSilently(Cursor cursor)232     public static void closeSilently(Cursor cursor) {
233         try {
234             if (cursor != null) cursor.close();
235         } catch (Throwable t) {
236             Log.w(TAG, "fail to close", t);
237         }
238     }
239 
interpolateAngle( float source, float target, float progress)240     public static float interpolateAngle(
241             float source, float target, float progress) {
242         // interpolate the angle from source to target
243         // We make the difference in the range of [-179, 180], this is the
244         // shortest path to change source to target.
245         float diff = target - source;
246         if (diff < 0) diff += 360f;
247         if (diff > 180) diff -= 360f;
248 
249         float result = source + diff * progress;
250         return result < 0 ? result + 360f : result;
251     }
252 
interpolateScale( float source, float target, float progress)253     public static float interpolateScale(
254             float source, float target, float progress) {
255         return source + progress * (target - source);
256     }
257 
ensureNotNull(String value)258     public static String ensureNotNull(String value) {
259         return value == null ? "" : value;
260     }
261 
262     // Used for debugging. Should be removed before submitting.
debug(String format, Object ... args)263     public static void debug(String format, Object ... args) {
264         if (args.length == 0) {
265             Log.d(DEBUG_TAG, format);
266         } else {
267             Log.d(DEBUG_TAG, String.format(format, args));
268         }
269     }
270 
parseFloatSafely(String content, float defaultValue)271     public static float parseFloatSafely(String content, float defaultValue) {
272         if (content == null) return defaultValue;
273         try {
274             return Float.parseFloat(content);
275         } catch (NumberFormatException e) {
276             return defaultValue;
277         }
278     }
279 
parseIntSafely(String content, int defaultValue)280     public static int parseIntSafely(String content, int defaultValue) {
281         if (content == null) return defaultValue;
282         try {
283             return Integer.parseInt(content);
284         } catch (NumberFormatException e) {
285             return defaultValue;
286         }
287     }
288 
isNullOrEmpty(String exifMake)289     public static boolean isNullOrEmpty(String exifMake) {
290         return TextUtils.isEmpty(exifMake);
291     }
292 
hasSpaceForSize(long size)293     public static boolean hasSpaceForSize(long size) {
294         String state = Environment.getExternalStorageState();
295         if (!Environment.MEDIA_MOUNTED.equals(state)) {
296             return false;
297         }
298 
299         String path = Environment.getExternalStorageDirectory().getPath();
300         try {
301             StatFs stat = new StatFs(path);
302             return stat.getAvailableBlocks() * (long) stat.getBlockSize() > size;
303         } catch (Exception e) {
304             Log.i(TAG, "Fail to access external storage", e);
305         }
306         return false;
307     }
308 
waitWithoutInterrupt(Object object)309     public static void waitWithoutInterrupt(Object object) {
310         try {
311             object.wait();
312         } catch (InterruptedException e) {
313             Log.w(TAG, "unexpected interrupt: " + object);
314         }
315     }
316 
shuffle(int array[], Random random)317     public static void shuffle(int array[], Random random) {
318         for (int i = array.length; i > 0; --i) {
319             int t = random.nextInt(i);
320             if (t == i - 1) continue;
321             int tmp = array[i - 1];
322             array[i - 1] = array[t];
323             array[t] = tmp;
324         }
325     }
326 
handleInterrruptedException(Throwable e)327     public static boolean handleInterrruptedException(Throwable e) {
328         // A helper to deal with the interrupt exception
329         // If an interrupt detected, we will setup the bit again.
330         if (e instanceof InterruptedIOException
331                 || e instanceof InterruptedException) {
332             Thread.currentThread().interrupt();
333             return true;
334         }
335         return false;
336     }
337 
338     /**
339      * @return String with special XML characters escaped.
340      */
escapeXml(String s)341     public static String escapeXml(String s) {
342         StringBuilder sb = new StringBuilder();
343         for (int i = 0, len = s.length(); i < len; ++i) {
344             char c = s.charAt(i);
345             switch (c) {
346                 case '<':  sb.append("&lt;"); break;
347                 case '>':  sb.append("&gt;"); break;
348                 case '\"': sb.append("&quot;"); break;
349                 case '\'': sb.append("&#039;"); break;
350                 case '&':  sb.append("&amp;"); break;
351                 default: sb.append(c);
352             }
353         }
354         return sb.toString();
355     }
356 
getUserAgent(Context context)357     public static String getUserAgent(Context context) {
358         PackageInfo packageInfo;
359         try {
360             packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
361         } catch (NameNotFoundException e) {
362             throw new IllegalStateException("getPackageInfo failed");
363         }
364         return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s",
365                 packageInfo.packageName,
366                 packageInfo.versionName,
367                 Build.BRAND,
368                 Build.DEVICE,
369                 Build.MODEL,
370                 Build.ID,
371                 Build.VERSION.SDK,
372                 Build.VERSION.RELEASE,
373                 Build.VERSION.INCREMENTAL);
374     }
375 
copyOf(String[] source, int newSize)376     public static String[] copyOf(String[] source, int newSize) {
377         String[] result = new String[newSize];
378         newSize = Math.min(source.length, newSize);
379         System.arraycopy(source, 0, result, 0, newSize);
380         return result;
381     }
382 
deserializePendingIntent(byte[] rawPendingIntent)383     public static PendingIntent deserializePendingIntent(byte[] rawPendingIntent) {
384         Parcel parcel = null;
385         try {
386             if (rawPendingIntent != null) {
387                 parcel = Parcel.obtain();
388                 parcel.unmarshall(rawPendingIntent, 0, rawPendingIntent.length);
389                 return PendingIntent.readPendingIntentOrNullFromParcel(parcel);
390             } else {
391                 return null;
392             }
393         } catch (Exception e) {
394             throw new IllegalArgumentException("error parsing PendingIntent");
395         } finally {
396             if (parcel != null) parcel.recycle();
397         }
398     }
399 
serializePendingIntent(PendingIntent pendingIntent)400     public static byte[] serializePendingIntent(PendingIntent pendingIntent) {
401         Parcel parcel = null;
402         try {
403             parcel = Parcel.obtain();
404             PendingIntent.writePendingIntentOrNullToParcel(pendingIntent, parcel);
405             return parcel.marshall();
406         } finally {
407             if (parcel != null) parcel.recycle();
408         }
409     }
410 
411     // Mask information for debugging only. It returns <code>info.toString()</code> directly
412     // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask ("****")
413     // in release build to protect the information (e.g. for privacy issue).
maskDebugInfo(Object info)414     public static String maskDebugInfo(Object info) {
415         if (info == null) return null;
416         String s = info.toString();
417         int length = Math.min(s.length(), MASK_STRING.length());
418         return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length);
419     }
420 }
421