Home | History | Annotate | Download | only in common
      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.
     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.
     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.
     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.
     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.
     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.
     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
    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).
    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].
    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].
    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].
    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 
    135     public static boolean isOpaque(int color) {
    136         return color >>> 24 == 0xFF;
    137     }
    138 
    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 
    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      */
    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 
    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 
    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 
    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 
    204     public static int compare(long a, long b) {
    205         return a < b ? -1 : a == b ? 0 : 1;
    206     }
    207 
    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 
    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 
    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 
    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 
    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 
    253     public static float interpolateScale(
    254             float source, float target, float progress) {
    255         return source + progress * (target - source);
    256     }
    257 
    258     public static String ensureNotNull(String value) {
    259         return value == null ? "" : value;
    260     }
    261 
    262     // Used for debugging. Should be removed before submitting.
    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 
    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 
    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 
    289     public static boolean isNullOrEmpty(String exifMake) {
    290         return TextUtils.isEmpty(exifMake);
    291     }
    292 
    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 
    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 
    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 
    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      */
    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 
    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 
    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 
    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 
    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).
    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