Managers.java
package net.zer0bandwidth.android.lib.app;
import android.accounts.AccountManager;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.DownloadManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.SearchManager;
import android.app.UiModeManager;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
import android.app.job.JobScheduler;
import android.app.usage.UsageStatsManager;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothManager;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.RestrictionsManager;
import android.content.pm.LauncherApps;
import android.hardware.ConsumerIrManager;
import android.hardware.SensorManager;
import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
import android.hardware.input.InputManager;
import android.hardware.usb.UsbManager;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaRouter;
import android.media.projection.MediaProjectionManager;
import android.media.session.MediaSessionManager;
import android.media.tv.TvInputManager;
import android.net.ConnectivityManager;
import android.net.nsd.NsdManager;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pManager;
import android.nfc.NfcManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.DropBoxManager;
import android.os.PowerManager;
import android.os.UserManager;
import android.os.Vibrator;
import android.os.storage.StorageManager;
import android.print.PrintManager;
import android.telecom.TelecomManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.CaptioningManager;
import android.view.inputmethod.InputMethodManager;
import android.view.textservice.TextServicesManager;
import java.util.HashMap;
/**
* Provides instances of Android OS managers.
*
* This class is largely irrelevant after Android API 23, which adds the new
* {@code getSystemService(Class)} method to the {@link Context} class.
* System service classes added after Android API 23 are not supported by this
* class; if you are using a system service added after API 23, then you should
* consider this class deprecated and use the new method in {@code Context}
* instead.
*
* For backward compatibility from Android API 14 onward, the class provides
* constant values for all static manager tags that were added to
* {@code Context} after API 14.
*
* @since zer0bandwidth-net/android 0.1.3 (#29)
*/
public class Managers
{
protected static final String LOG_TAG = Managers.class.getSimpleName() ;
/// Android API 16 Constants ///////////////////////////////////////////////////
/**
* Backward-compatibility constant for {@code Context.INPUT_SERVICE}
* (added in Android API 16)
*/
public static final String INPUT_SERVICE = "input" ;
/**
* Backward-compatibility constant for {@code Context.MEDIA_ROUTER_SERVICE}
* (added in Android API 16)
*/
public static final String MEDIA_ROUTER_SERVICE = "media_router" ;
/**
* Backward-compatibility constant for {@code Context.NSD_SERVICE}
* (added in Android API 16)
*/
public static final String NSD_SERVICE = "servicediscovery" ;
/// Android API 17 Constants ///////////////////////////////////////////////////
/**
* Backward-compatibility constant for {@code Context.DISPLAY_SERVICE}
* (added in Android API 17)
*/
public static final String DISPLAY_SERVICE = "display" ;
/**
* Backward-compatibility constant for {@code Context.USER_SERVICE}
* (added in Android API 17)
*/
public static final String USER_SERVICE = "user" ;
/// Android API 18 Constants ///////////////////////////////////////////////////
/**
* Backward-compatibility constant for {@code Context.BLUETOOTH_SERVICE}
* (added in Android API 18)
*/
public static final String BLUETOOTH_SERVICE = "bluetooth" ;
/// Android API 19 Constants ///////////////////////////////////////////////////
/**
* Backward-compatibility constant for {@code Context.APP_OPS_SERVICE}
* (added in Android API 19)
*/
public static final String APP_OPS_SERVICE = "appops" ;
/**
* Backward-compatibility constant for {@code Context.CAPTIONING_SERVICE}
* (added in Android API 19)
*/
public static final String CAPTIONING_SERVICE = "captioning" ;
/**
* Backward-compatibility constant for {@code Context.CONSUMER_IR_SERVICE}
* (added in Android API 19)
*/
public static final String CONSUMER_IR_SERVICE = "consumer_ir" ;
/**
* Backward-compatibility constant for {@code Context.PRINT_SERVICE}
* (added in Android API 19)
*/
public static final String PRINT_SERVICE = "print" ;
/// Android API 21 Constants ///////////////////////////////////////////////////
/**
* Backward-compatibility constant for {@code Context.APPWIDGET_SERVICE}
* (added in Android API 21)
*/
public static final String APPWIDGET_SERVICE = "appwidget" ;
/**
* Backward-compatibility constant for {@code Context.BATTERY_SERVICE}
* (added in Android API 21)
*/
public static final String BATTERY_SERVICE = "batterymanager" ;
/**
* Backward-compatibility constant for {@code Context.CAMERA_SERVICE}
* (added in Android API 21)
*/
public static final String CAMERA_SERVICE = "camera" ;
/**
* Backward-compatibility constant for {@code Context.JOB_SCHEDULER_SERVICE}
* (added in Android API 21)
*/
public static final String JOB_SCHEDULER_SERVICE = "taskmanager" ;
/**
* Backward-compatibility constant for {@code Context.LAUNCHER_APPS_SERVICE}
* (added in Android API 21)
*/
public static final String LAUNCHER_APPS_SERVICE = "launcherapps" ;
/**
* Backward-compatibility constant for {@code Context.MEDIA_PROJECTION_SERVICE}
* (added in Android API 21)
*/
public static final String MEDIA_PROJECTION_SERVICE = "media_projection" ;
/**
* Backward-compatibility constant for {@code Context.MEDIA_SESSION_SERVICE}
* (added in Android API 21)
*/
public static final String MEDIA_SESSION_SERVICE = "media_session" ;
/**
* Backward-compatibility constant for {@code Context.RESTRICTIONS_SERVICE}
* (added in Android API 21)
*/
public static final String RESTRICTIONS_SERVICE = "restrictions" ;
/**
* Backward-compatibility constant for {@code Context.TELECOM_SERVICE}
* (added in Android API 21)
*/
public static final String TELECOM_SERVICE = "telecom" ;
/**
* Backward-compatibility constant for {@code Context.TV_INPUT_SERVICE}
* (added in Android API 21)
*/
public static final String TV_INPUT_SERVICE = "tv_input" ;
/// Android API 22 Constants ///////////////////////////////////////////////////
/**
* Backward-compatibility constant for {@code Context.TELECOM_SUBSCRIPTION_SERVICE}
* (added in Android API 22)
*/
public static final String TELEPHONY_SUBSCRIPTION_SERVICE =
"telephony_subscription_service" ;
/**
* Backward-compatibility constant for {@code Context.USAGE_STATS_SERVICE}
* (added in Android API 22)
*/
public static final String USAGE_STATS_SERVICE = "usagestats" ;
/// And now, the interesting bits //////////////////////////////////////////////
/**
* Defines a reverse mapping from class definitions to the constants by
* which they are identified in {@link Context}. Where those constants are
* not defined until later API versions, the map instead uses one of the
* compatibility constants defined in this class.
*
* <h3>Documentation Conflicts</h3>
*
* The following errors in the Android API documentation for {@code Context}
* were observed during unit testing.
*
* <table>
* <thead>
* <tr>
* <th>Context Token</th>
* <th>Documented Class</th>
* <th>Actual Class</th>
* <th>Resolution</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>{@link Context#SENSOR_SERVICE}</td>
* <td>{@link SensorManager}</td>
* <td>{@code android.hardware.SystemSensorManager}</td>
* <td>The actual class is assignable.</td>
* </tr>
* <tr>
* <td>{@link Context#WALLPAPER_SERVICE}</td>
* <td>{@link android.service.wallpaper.WallpaperService}</td>
* <td>{@link WallpaperManager}</td>
* <td>
* The returned class is not assignable; the map uses
* {@code WallpaperManager} <b>instead of</b>
* {@code WallpaperService}.
* </td>
* </tr>
* </tbody>
* </table>
*
* This map is instantiated only when the app's API version is lower than
* 23. When greater than 23, the {@link #get} method will simply call the
* existing {@code getSystemService(Class)} method in the API 23+ version of
* {@code Context}, so the map would not need to be populated.
*
* @see Context
*/
public static HashMap<Class<?>,String> REVERSE_MAP ;
static // initializer for REVERSE_MAP; executes only if needed
{
if( Build.VERSION.SDK_INT < Build.VERSION_CODES.M )
initReverseMap( Build.VERSION.SDK_INT ) ;
}
/**
* Initializes the reverse mapping of manager classes to constants from the
* {@link Context} class. Invoked by a static initializer for the class
* itself; the method is not intended to be called directly, except in unit
* testing scenarios.
* @param nVersion (since 0.2.1/#53) the environment's current SDK
* version; passed in as a parameter solely to support testing. See how
* this is used "normally" in the static initializer.
*/
@SuppressLint( "NewApi" ) // Build version managed via switch() control.
protected static void initReverseMap( int nVersion )
{
REVERSE_MAP = new HashMap<>() ;
Log.d( LOG_TAG, (new StringBuilder())
.append( "Loading reverse map for Android API " )
.append( nVersion )
.toString()
);
switch( nVersion )
{ // Fall through cases in reverse, populating each API's new classes.
case 22:
REVERSE_MAP.put( SubscriptionManager.class, TELEPHONY_SUBSCRIPTION_SERVICE ) ;
REVERSE_MAP.put( UsageStatsManager.class, USAGE_STATS_SERVICE ) ;
case 21:
REVERSE_MAP.put( AppWidgetManager.class, APPWIDGET_SERVICE ) ;
REVERSE_MAP.put( BatteryManager.class, BATTERY_SERVICE ) ;
REVERSE_MAP.put( CameraManager.class, CAMERA_SERVICE ) ;
REVERSE_MAP.put( JobScheduler.class, JOB_SCHEDULER_SERVICE ) ;
REVERSE_MAP.put( LauncherApps.class, LAUNCHER_APPS_SERVICE ) ;
REVERSE_MAP.put( MediaProjectionManager.class, MEDIA_PROJECTION_SERVICE ) ;
REVERSE_MAP.put( MediaSessionManager.class, MEDIA_SESSION_SERVICE ) ;
REVERSE_MAP.put( RestrictionsManager.class, RESTRICTIONS_SERVICE ) ;
REVERSE_MAP.put( TelecomManager.class, TELECOM_SERVICE ) ;
REVERSE_MAP.put( TvInputManager.class, TV_INPUT_SERVICE ) ;
case 20:
case 19:
REVERSE_MAP.put( AppOpsManager.class, APP_OPS_SERVICE ) ;
REVERSE_MAP.put( CaptioningManager.class, CAPTIONING_SERVICE ) ;
REVERSE_MAP.put( ConsumerIrManager.class, CONSUMER_IR_SERVICE ) ;
REVERSE_MAP.put( PrintManager.class, PRINT_SERVICE ) ;
case 18:
REVERSE_MAP.put( BluetoothManager.class, BLUETOOTH_SERVICE ) ;
case 17:
REVERSE_MAP.put( DisplayManager.class, DISPLAY_SERVICE ) ;
REVERSE_MAP.put( UserManager.class, USER_SERVICE ) ;
case 16:
REVERSE_MAP.put( InputManager.class, INPUT_SERVICE );
REVERSE_MAP.put( MediaRouter.class, MEDIA_ROUTER_SERVICE );
REVERSE_MAP.put( NsdManager.class, NSD_SERVICE );
default: // No new managers in API 15; library minimum is 14.
REVERSE_MAP.put( AccessibilityManager.class, Context.ACCESSIBILITY_SERVICE ) ;
REVERSE_MAP.put( AccountManager.class, Context.ACCOUNT_SERVICE ) ;
REVERSE_MAP.put( ActivityManager.class, Context.ACTIVITY_SERVICE ) ;
REVERSE_MAP.put( AlarmManager.class, Context.ALARM_SERVICE ) ;
REVERSE_MAP.put( AudioManager.class, Context.AUDIO_SERVICE ) ;
REVERSE_MAP.put( ClipboardManager.class, Context.CLIPBOARD_SERVICE ) ;
REVERSE_MAP.put( ConnectivityManager.class, Context.CONNECTIVITY_SERVICE ) ;
REVERSE_MAP.put( DevicePolicyManager.class, Context.DEVICE_POLICY_SERVICE ) ;
REVERSE_MAP.put( DownloadManager.class, Context.DOWNLOAD_SERVICE ) ;
REVERSE_MAP.put( DropBoxManager.class, Context.DROPBOX_SERVICE ) ;
REVERSE_MAP.put( InputMethodManager.class, Context.INPUT_METHOD_SERVICE ) ;
REVERSE_MAP.put( KeyguardManager.class, Context.KEYGUARD_SERVICE ) ;
REVERSE_MAP.put( LayoutInflater.class, Context.LAYOUT_INFLATER_SERVICE ) ;
REVERSE_MAP.put( LocationManager.class, Context.LOCATION_SERVICE ) ;
REVERSE_MAP.put( NfcManager.class, Context.NFC_SERVICE ) ;
REVERSE_MAP.put( NotificationManager.class, Context.NOTIFICATION_SERVICE ) ;
REVERSE_MAP.put( PowerManager.class, Context.POWER_SERVICE ) ;
REVERSE_MAP.put( SearchManager.class, Context.SEARCH_SERVICE ) ;
REVERSE_MAP.put( SensorManager.class, Context.SENSOR_SERVICE ) ;
REVERSE_MAP.put( StorageManager.class, Context.STORAGE_SERVICE ) ;
REVERSE_MAP.put( TelephonyManager.class, Context.TELEPHONY_SERVICE ) ;
REVERSE_MAP.put( TextServicesManager.class, Context.TEXT_SERVICES_MANAGER_SERVICE ) ;
REVERSE_MAP.put( UiModeManager.class, Context.UI_MODE_SERVICE ) ;
REVERSE_MAP.put( UsbManager.class, Context.USB_SERVICE ) ;
REVERSE_MAP.put( Vibrator.class, Context.VIBRATOR_SERVICE ) ;
REVERSE_MAP.put( WallpaperManager.class, Context.WALLPAPER_SERVICE ) ;
REVERSE_MAP.put( WifiManager.class, Context.WIFI_SERVICE ) ;
REVERSE_MAP.put( WifiP2pManager.class, Context.WIFI_P2P_SERVICE ) ;
REVERSE_MAP.put( WindowManager.class, Context.WINDOW_SERVICE ) ;
}
}
/**
* Obtains an instance of the Android OS service whose class is given.
*
* If the app's API version is already 23 or higher, then the method will
* simply call the new {@code getSystemService(Class)} method instead of
* executing its own compatibility logic.
*
* The return value of this method is already an instance of the type
* specified in the parameter; there is no need for additional typecasting
* after the instance is returned to the caller. This is exactly how the
* {@code getSystemService(Class)} method works in the API 23+ version of
* {@link Context}.
*
* @param ctx the context in which to obtain the service
* @param cls the class to be obtained, as a parameter
* @param <MGR> the class to be obtained, as a generic return type
* @return an instance of the specified class, or null if the system does
* not return an instance
*/
@SuppressWarnings({ "unchecked", "WrongConstant" })
public static <MGR> MGR get( Context ctx, Class<MGR> cls )
{
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.M )
return ctx.getSystemService( cls ) ;
if( REVERSE_MAP.containsKey(cls) )
return ((MGR)( ctx.getSystemService( REVERSE_MAP.get(cls) ) )) ;
else
{
Log.w( LOG_TAG, (new StringBuilder())
.append( "Cannot obtain instance of class [" )
.append( cls.getCanonicalName() )
.append( "] not found in the reverse map." )
.toString()
);
return null ;
}
}
/**
* As {@link #get}, but executes the action inside a
* {@code try…catch} structure, returning {@code null} if an
* exception is thrown
* @param ctx the context in which to obtain the service
* @param cls the class to be obtained, as a parameter
* @param <MGR> the class to be obtained, as a generic return type
* @return an instance of the specified class, or null if the system does
* not return an instance, or null if an exception occurred
*/
public static <MGR> MGR tryToGet( Context ctx, Class<MGR> cls )
{
try { return get( ctx, cls ) ; }
catch( Exception x )
{
Log.e( LOG_TAG, (new StringBuilder())
.append( "Exception thrown while obtaining instance of " )
.append( cls.getCanonicalName() )
.toString()
, x ) ;
return null ;
}
}
}