package waymaker.gen; // Copyright © 2016 Michael Allan. Licence MIT. import android.content.*; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.widget.TextView; import java.lang.reflect.Field; import static android.content.SharedPreferences.OnSharedPreferenceChangeListener; /** Utilities for working with Android. */ public @ThreadSafe final class Android { private Android() {} /** The maximum value of an alpha component, meaning “fully opaque”. * * @see Drawable.getAlpha */ public static final int ALPHA_OPAQUE = 255; /** Calculates the bottom bound (exclusive) of a graphical component from its top position * (inclusive) and height. * * @see View.getTop * @see View.getBottom */ public static int bottom( final int top, final int height ) { return top + height; } // undocumented /** Returns the requested service, or throws a NullPointerException if the service is unavailable in * the given context. This is a convenience method. * * @see Context.getSystemService */ public static final T ensureSystemService( final Class serviceClass, final Context context ) { final T service = context.getSystemService( serviceClass ); if( service == null ) throw new IllegalStateException(); return service; } /** Calculates the height of a graphical component from its top position (inclusive) and bottom * bound (exclusive). * * @see View.getTop * @see View.getBottom */ public static int height( final int top, final int bottom ) { return bottom - top; } // undocumented /** Returns a string representation of the given Intent flags. Inefficient, this method is meant * only for test purposes. * * @see getFlags */ public static @Warning("non-API") String intentFlagsToString( final int flags ) { // after joecks, https://gist.github.com/joecks/4559331 final int countEncoded = Integer.bitCount( flags ); String s = Integer.toString(countEncoded) + " flags"; if( flags > 0 ) { s += " including"; int countNamed = 0; for( final Field field: Intent.class.getDeclaredFields() ) { if( !field.getName().startsWith( "FLAG_" )) continue; try { final int flag = field.getInt( null ); if( (flag & flags) == 0 ) continue; s += " "; s += field.getName(); if( Integer.bitCount(flag) == 1 ) ++countNamed; // count only 1-bit flags, just in case } catch( final IllegalAccessException x ) { throw new RuntimeException( x ); } } for( int c = countNamed; c < countEncoded; ++c ) s += " UNDECLARED"; } return s; } /** Converts HSV colour components to an ARGB colour. This convenience method passes the arguments * through a common array, restricted to the application main thread. * * @see Color.HSVToColor */ @ThreadRestricted("app main") public static int HSVToColor( final float hue, final float saturation, final float value ) { triFloat[0] = hue; triFloat[1] = saturation; triFloat[2] = value; return Color.HSVToColor( ALPHA_OPAQUE, triFloat ); } /** Creates a text view with the given text. This is a convenience method. */ public static TextView newTextView( final String text, final Context context ) { final TextView view = new TextView( context ); view.setText( text ); return view; } /** Sets a uniform padding on the view. This is a convenience method. * * @see View.setPadding */ public static void pad( final View view, final int p ) { view.setPadding( p, p, p, p ); } /** Registers the listener with the preference store and ensures it will be unregistered on * destruction. This is a convenience method that creates a separate destructible for the * unregistration and adds it to the given destructor. Thereby it also defeats the {@linkplain * ApplicationX#preferences() weak reference} in the store register. */ public static void registerDestructibly( final SharedPreferences preferenceStore, final OnSharedPreferenceChangeListener listener, final Destructor destructor ) { preferenceStore.registerOnSharedPreferenceChangeListener( listener ); destructor.add( new Destructible() { public void close() { preferenceStore.unregisterOnSharedPreferenceChangeListener( listener ); } }); } /** Calculates the right bound (exclusive) of a graphical component from its left position * (inclusive) and width. * * @see View.getLeft * @see View.getRight */ public static int right( final int left, final int width ) { return left + width; } // undocumented /** Returns the given bundle, or an immutable, empty surrogate if the bundle is null. */ public static Bundle unnull( final Bundle bun ) { return bun == null? Bundle.EMPTY: bun; } // Bundle.EMPTY is immutable (undocumented in Android 23) owing to use of ArrayMap.EMPTY /** Calculates the width of a graphical component from its left position (inclusive) and right bound * (exclusive). * * @see View.getLeft * @see View.getRight */ public static int width( final int left, final int right ) { return right - left; } // undocumented //// P r i v a t e ///////////////////////////////////////////////////////////////////////////////////// private static @ThreadRestricted("app main") final float[] triFloat = new float[3]; }