package info.guardianproject.securereaderinterface.uiutil; import info.guardianproject.securereaderinterface.widgets.NestedViewPager; import info.guardianproject.securereaderinterface.R; import info.guardianproject.iocipher.File; import info.guardianproject.iocipher.FileInputStream; import java.io.BufferedInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.DateFormat; import java.util.Date; import javax.microedition.khronos.egl.EGLContext; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Point; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.opengl.GLES20; import android.os.Build; import android.support.v4.view.ViewCompat; import android.text.SpannableStringBuilder; import android.text.style.CharacterStyle; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.Window; import android.view.inputmethod.InputMethodManager; public class UIHelpers { public static int dpToPx(int dp, Context ctx) { Resources r = ctx.getResources(); return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()); } public static String dateDateDisplayString(Date date, Context context) { if (date == null) return ""; return DateFormat.getDateInstance().format(date); } public static String dateTimeDisplayString(Date date, Context context) { if (date == null) return ""; return DateFormat.getTimeInstance().format(date); } public static String dateDiffDisplayString(Date date, Context context, int idStringNever, int idStringRecently, int idStringMinutes, int idStringMinute, int idStringHours, int idStringHour, int idStringDays, int idStringDay) { if (date == null) return ""; Date todayDate = new Date(); double ti = todayDate.getTime() - date.getTime(); if (ti < 0) ti = -ti; ti = ti / 1000; // Convert to seconds if (ti < 1) { return context.getString(idStringNever); } else if (ti < 60) { return context.getString(idStringRecently); } else if (ti < 3600 && (int) Math.round(ti / 60) < 60) { int diff = (int) Math.round(ti / 60); if (diff == 1) return context.getString(idStringMinute, diff); return context.getString(idStringMinutes, diff); } else if (ti < 86400 && (int) Math.round(ti / 60 / 60) < 24) { int diff = (int) Math.round(ti / 60 / 60); if (diff == 1) return context.getString(idStringHour, diff); return context.getString(idStringHours, diff); } else // if (ti < 2629743) { int diff = (int) Math.round(ti / 60 / 60 / 24); if (diff == 1) return context.getString(idStringDay, diff); return context.getString(idStringDays, diff); } // else // { // return context.getString(idStringNever); // } } public static int getRelativeLeft(View myView) { if (myView.getParent() == myView.getRootView()) return myView.getLeft(); else return myView.getLeft() + UIHelpers.getRelativeLeft((View) myView.getParent()); } public static int getRelativeTop(View myView) { if (myView.getParent() == myView.getRootView()) return myView.getTop(); else return myView.getTop() + UIHelpers.getRelativeTop((View) myView.getParent()); } /** * Get the coordinates of a view relative to another anchor view. The anchor * view is assumed to be in the same view tree as this view. * * @param anchorView * View relative to which we are getting the coordinates * @param view * The view to get the coordinates for * @return A Rect containing the view bounds */ public static Rect getRectRelativeToView(View anchorView, View view) { Rect ret = new Rect(getRelativeLeft(view) - getRelativeLeft(anchorView), getRelativeTop(view) - getRelativeTop(anchorView), 0, 0); ret.right = ret.left + view.getWidth(); ret.bottom = ret.top + view.getHeight(); return ret; } public static int getStatusBarHeight(Activity activity) { Rect rectContent = new Rect(); Window window = activity.getWindow(); window.getDecorView().getWindowVisibleDisplayFrame(rectContent); return rectContent.top; } // From. // http://www.androidengineer.com/2010/08/easy-method-for-formatting-android.html /** * Given either a Spannable String or a regular String and a token, apply * the given CharacterStyle to the span between the tokens, and also remove * tokens. * <p> * For example, {@code setSpanBetweenTokens("Hello ##world##!", "##", * new ForegroundColorSpan(0xFFFF0000));} will return a CharSequence * {@code "Hello world!"} with {@code world} in red. * * @param text * The text, with the tokens, to adjust. * @param token * The token string; there should be at least two instances of * token in text. * @param cs * The style to apply to the CharSequence. WARNING: You cannot * send the same two instances of this parameter, otherwise the * second call will remove the original span. * @return A Spannable CharSequence with the new style applied. * * @see http * ://developer.android.com/reference/android/text/style/CharacterStyle * .html */ public static CharSequence setSpanBetweenTokens(CharSequence text, String token, CharacterStyle... cs) { // Start and end refer to the points where the span will apply int tokenLen = token.length(); int start = text.toString().indexOf(token) + tokenLen; int end = text.toString().indexOf(token, start); if (start > -1 && end > -1) { // Copy the spannable string to a mutable spannable string SpannableStringBuilder ssb = new SpannableStringBuilder(text); for (CharacterStyle c : cs) ssb.setSpan(c, start, end, 0); // Delete the tokens before and after the span ssb.delete(end, end + tokenLen); ssb.delete(start - tokenLen, start); text = ssb; } return text; } public static void colorizeDrawable(Context context, Drawable drawable) { if (drawable == null) return; TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.actionBarThemeColorIconTint, outValue, true); if ((outValue.data & 0xff000000) != 0) drawable.setColorFilter(outValue.data, Mode.SRC_ATOP); else drawable.setColorFilter(null); } private static Point gMaxGLSize; @SuppressLint("NewApi") private static Point getMaxGLSize(Context context) { if (gMaxGLSize == null) { // TODO - getMaximumBitmapWidth returns width for a software rendered canvas below, so no use to us. // if (Build.VERSION.SDK_INT >= 14) // { // Bitmap bmp = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Canvas c = new Canvas(bmp); // gMaxGLSize = new Point(c.getMaximumBitmapWidth(), c.getMaximumBitmapHeight()); // } // else { // Try the GL approach // int[] buf = new int[1]; EGLContext.getEGL(); GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, buf, 0); int glSize = buf[0]; if (glSize < 1) { Log.v("UIHelpers", "GL Max texture size returned 0!"); int rounded = (int)(2048f / context.getResources().getDisplayMetrics().density); gMaxGLSize = new Point(rounded, rounded); } else { gMaxGLSize = new Point(glSize, glSize); } } } return gMaxGLSize; } public static Bitmap scaleToMaxGLSize(Context context, File mediaFile, int width, int height) { try { // Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BufferedInputStream bis = new BufferedInputStream(new FileInputStream(mediaFile)); BitmapFactory.decodeStream(bis, null, o); bis.close(); Point maxSize = getMaxGLSize(context); int scale = 1; if (o.outWidth > maxSize.x || o.outHeight > maxSize.y) { // Find the correct scale value. It should be the power of 2. int width_tmp = o.outWidth, height_tmp = o.outHeight; while (true) { if (width_tmp < maxSize.x && height_tmp < maxSize.y) { break; } width_tmp /= 2; height_tmp /= 2; scale *= 2; } } int scaleIV = 1; if (width > 0 && height > 0) { int heightRatio = (int) Math.ceil(o.outHeight / (float) height); int widthRatio = (int) Math.ceil(o.outWidth / (float) width); if (heightRatio > 1 && widthRatio > 1) { if (heightRatio > widthRatio) { scaleIV = heightRatio; } else { scaleIV = widthRatio; } } } // Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = Math.max(scale, scaleIV); //return BitmapFactory.decodeFile(mediaFile.getAbsolutePath(), o2); BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(mediaFile)); Bitmap returnBitmap = BitmapFactory.decodeStream(bis2, null, o2); bis2.close(); return returnBitmap; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } @SuppressLint("NewApi") public static boolean canScrollHorizontally(View v, int direction) { if (Build.VERSION.SDK_INT >= 14) { return v.canScrollHorizontally(direction); } else { // Check for method! try { if (v instanceof NestedViewPager) return ((NestedViewPager) v).canScrollHorizontally(direction); Method m = v.getClass().getMethod("canScrollHorizontally", int.class); if (m != null) return (Boolean) m.invoke(v, direction); } catch (NoSuchMethodException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } } return ViewCompat.canScrollHorizontally(v, direction); } public static void hideSoftKeyboard(Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); View view = activity.getCurrentFocus(); if (view != null) inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); } }