package waymaker.gen; // Copyright © 2015 Michael Allan. Licence MIT. import android.app.Application; import android.content.SharedPreferences; import android.graphics.Rect; import android.util.*; import android.os.*; import java.util.concurrent.atomic.AtomicReference; /** An Android application with member extensions. */ public @ThreadSafe class ApplicationX extends Application { /** Constructs the {@linkplain #i() single instance} of ApplicationX. This constructor is called by * the Android runtime during initialization of the actual application as commanded in the manifest * file AndroidManifest.xml. * * @throws IllegalStateException if an instance was already constructed. */ public @Warning("non-API") ApplicationX() { mainLooper = Looper.getMainLooper(); handler = new Handler( mainLooper ); } static { System.setProperty( "waymaker.g.LoggerX.classPrefix", "wm" ); } // early init: before LoggerX loads, rename the class-based loggers from "PACKAGE.CLASS", which // Android logcat tags simply as "CLASS", to "wmCLASS" instead // ` c r e a t i o n ```````````````````````````````````````````````````````````````````````````````` public @Override @Warning("non-API") void onCreate() { super.onCreate(); // obeying API if( !isMainThread() ) throw new IllegalStateException(); // at least for visibility of this.preferences preferences = getSharedPreferences( /*name*/"app", /*mode, typical*/MODE_PRIVATE ); final DisplayMetrics metrics = getResources().getDisplayMetrics(); pxDP = metrics.density; final float px_per_mm = metrics.xdpi/*px/inch*/ / (General.CM_PER_INCH * 10)/*mm/inch*/; px7mmX = (int)Math.ceil( 7/*mm*/ * px_per_mm ); px9mmX = (int)Math.ceil( 9/*mm*/ * px_per_mm ); } // -------------------------------------------------------------------------------------------------- /** A handler for communicating with the application’s main thread. * * @see runOnUiThread * @see AsyncTask */ public final Handler handler() { return handler; } private final Handler handler; /** The single instance of ApplicationX as created by the Android runtime, or null if there is none. */ public static ApplicationX i() { return instanceA.get(); } private static final AtomicReference instanceA = new AtomicReference<>(); { if( !instanceA.compareAndSet( null, this )) throw new IllegalStateException(); } /** Answers whether the current thread is the application main thread. */ public final boolean isMainThread() { // return mainLooper.isCurrentThread(); /// assumes API level 23 return Thread.currentThread() == mainLooper.getThread(); } /** Answers whether an application might run remotely from a server, as during normal use, as * opposed to local testing. Currently this is false. Assert it as false from any code that might * break on remote usage provided the fix can reasonably be deferred. * * @see #setRemotelyUsable() */ public static boolean isRemotelyUsable() { return isRemotelyUsable; } private static volatile boolean isRemotelyUsable; /** Establishes that an application might run remotely from a server. * * @see #isRemotelyUsable() */ public static void setRemotelyUsable() { isRemotelyUsable = true; } /** The general preference store for this application. Be aware that it registers its listeners by * weak reference. Registration alone is therefore insufficient * to prevent premature finalization and effective unregistration of the listener. * Something else must hold a strong reference to it, such as an unregistration destructible. */ public @ThreadRestricted("app main") final SharedPreferences preferences() { return preferences; } private SharedPreferences preferences; // final after onCreate // no cost to hold this ref because any getSharedPreferences will "hold" it anyway /** Returns either the given width or px7mmX, whichever is greater. The value * px7mmX is the minimum width (as measured in physical pixels) that is not less than * 7 mm. This is recommended as the absolute minimum for touch targets, demanding some care on the * part of the user, e.g. touching with the tip of the index finger. * * @param pxWidth The given width as measured in physical pixels. * @see Touch Target Sizes */ public final int px7mmExtendedWidth( final int pxWidth ) { return Math.max( pxWidth, px7mmX ); } private volatile int px7mmX; // final after onCreate /** Returns either the given width or px9mmX, whichever is greater. The value * px9mmX is the minimum width (as measured in physical pixels) that is not less than * 9 mm. This is recommended as the general minimum for touch targets. * * @param pxWidth The given width as measured in physical pixels. * @see Touch Target Sizes */ public final int px9mmExtendedWidth( final int pxWidth ) { return Math.max( pxWidth, px9mmX ); } private volatile int px9mmX; // final after onCreate /** The size of a density-independent pixel as measured in physical pixels. Returns the value of * getResources.getDisplayMetrics.density * cached (for speed) when this application was created. * * @see ActivityX#pxSP() * @see Resources § Dimension */ public final float pxDP() { return pxDP; } private volatile float pxDP; // final after onCreate /** A common rectangle for isolated use on the application main thread. */ public @Warning("thread restricted object, app main") final Rect rect() { return rect; } private final Rect rect = new Rect(); /** Clears and returns a common string builder for isolated use on the application main thread. * Consider calling {@linkplain StringBuilder#trimToSize trimToSize} after building a large string. */ @ThreadRestricted("app main") public final StringBuilder stringBuilderClear() { return StringBuilderX.clear( stringBuilder ); } private final StringBuilder stringBuilder = new StringBuilder(); /** A common value container for isolated use on the application main thread. */ public @Warning("thread restricted object, app main") final TypedValue typedValue() { return typedValue; } private final TypedValue typedValue = new TypedValue(); //// P r i v a t e ///////////////////////////////////////////////////////////////////////////////////// private final Looper mainLooper; // store to avoid sync in Looper.getMainLooper (API level 23 source) }