2929import androidx .annotation .NonNull ;
3030import androidx .annotation .RequiresApi ;
3131
32+ import com .microsoft .identity .common .logging .Logger ;
33+
34+ import java .util .Map ;
35+ import java .util .concurrent .ConcurrentHashMap ;
36+
3237/**
3338 * Wrapper class for PowerManager.
3439 */
3540
3641public class PowerManagerWrapper {
3742
43+ private static final String TAG = PowerManagerWrapper .class .getSimpleName ();
44+
3845 private static PowerManagerWrapper sInstance ;
3946
4047 private static final String UNKNOWN_STATUS = "Unknown" ;
48+
49+ // In-memory cache for battery optimization status (now stores String results)
50+ private final Map <String , String > batteryOptOutCache = new ConcurrentHashMap <>();
4151 /**
4252 * Set instance of PowerManagerWrapper.
4353 *
@@ -107,10 +117,6 @@ public String getDeviceIdleMode(@NonNull final Context context){
107117 @ NonNull
108118 public String getPowerOptimizationSettings (@ NonNull final Context context ){
109119 try {
110- if (Build .VERSION .SDK_INT < Build .VERSION_CODES .M ) {
111- return UNKNOWN_STATUS ;
112- }
113-
114120 final PowerManager powerManager = ((PowerManager ) context .getSystemService (Context .POWER_SERVICE ));
115121 if (powerManager .isIgnoringBatteryOptimizations (context .getPackageName ())){
116122 return "OptOut" ;
@@ -134,4 +140,40 @@ public String getPowerOptimizationSettings(@NonNull final Context context){
134140 public boolean isIgnoringBatteryOptimizations (final Context connectionContext ) {
135141 return ((PowerManager ) connectionContext .getSystemService (Context .POWER_SERVICE )).isIgnoringBatteryOptimizations (connectionContext .getPackageName ());
136142 }
143+
144+ /**
145+ * Checks if the app with the given package name is opted out from battery optimization.
146+ * Caches the result in memory using computeIfAbsent for thread safety.
147+ * Returns a string indicating the result or exception type.
148+ *
149+ * @param packageName The package name to check.
150+ * @param context The context to use for PowerManager.
151+ * @return "OptedOut" if the app is opted out, "NotOptedOut" if not, or exception type string.
152+ */
153+ public String isAppOptedOutFromBatteryOptimization (@ NonNull final String packageName , @ NonNull final Context context ) {
154+ final String methodTag = TAG + ":isAppOptedOutFromBatteryOptimization" ;
155+
156+ return batteryOptOutCache .computeIfAbsent (packageName , key -> {
157+ try {
158+ final PowerManager powerManager = (PowerManager ) context .getSystemService (Context .POWER_SERVICE );
159+ if (powerManager .isIgnoringBatteryOptimizations (key )) {
160+ return "OptOut" ;
161+ } else {
162+ return "NotOptOut" ;
163+ }
164+ } catch (NullPointerException e ) {
165+ Logger .error (methodTag , "NullPointerException when checking battery optimization status for package: " + packageName , e );
166+ return "NullPointerException" ;
167+ } catch (SecurityException e ) {
168+ Logger .error (methodTag , "SecurityException when checking battery optimization status for package: " + packageName , e );
169+ return "SecurityException" ;
170+ } catch (IllegalArgumentException e ) {
171+ Logger .error (methodTag , "IllegalArgumentException when checking battery optimization status for package: " + packageName , e );
172+ return "IllegalArgumentException" ;
173+ } catch (Exception e ) {
174+ Logger .error (methodTag , "Unknown Exception when checking battery optimization status for package: " + packageName , e );
175+ return "UnknownException" ;
176+ }
177+ });
178+ }
137179}
0 commit comments