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