content: package com.achep.base.utils.power;
  
  import android.annotation.TargetApi;
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.os.Build;
  import android.os.PowerManager;
  import androidx.annotation.NonNull;
  
  import com.achep.acdisplay.Atomic;
  import com.achep.base.Device;
  import com.achep.base.interfaces.IPowerSave;
  import com.achep.base.interfaces.ISubscriptable;
  
  import java.util.ArrayList;
  
  import static com.achep.base.Build.DEBUG_POWER_SAVING;
  
  /**
   * @author Artem Chepurnoy
   */
  public abstract class PowerSaveDetector implements
          ISubscriptable<PowerSaveDetector.OnPowerSaveChanged>,
          IPowerSave {
  
      private static boolean sPowerSaveMode;
  
      @NonNull
      public static PowerSaveDetector newInstance(@NonNull Context context) {
          return Device.hasLollipopApi()
                  ? new PowerSaveLollipop(context)
                  : new PowerSaveCompat(context);
      }
  
      /**
       * Returns {@code true} if the device is currently in power save mode.
       * When in this mode, applications should reduce their functionality
       * in order to conserve battery as much as possible.
       *
       * @return {@code true} if the device is currently in power save mode, {@code false} otherwise.
       */
      public static boolean isPowerSaving() {
          return sPowerSaveMode;
      }
  
      /**
       * Inverse function to {@link #isPowerSaveMode()}
       */
      /*
       * I hate using `if (!...)` construction so this
       * method was created
       */
      public static boolean isNotPowerSaving() {
          return !isPowerSaving();
      }
  
      protected final ArrayList<OnPowerSaveChanged> mListeners;
      protected final Context mContext;
      protected boolean mPowerSaveMode;
  
      /**
       * @author Artem Chepurnoy
       */
      public interface OnPowerSaveChanged {
  
          void onPowerSaveChanged(boolean powerSaving);
      }
  
      private PowerSaveDetector(@NonNull Context context) {
          mListeners = new ArrayList<>();
          mContext = context;
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public void registerListener(@NonNull OnPowerSaveChanged listener) {
          mListeners.add(listener);
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public void unregisterListener(@NonNull OnPowerSaveChanged listener) {
          mListeners.remove(listener);
      }
  
      public abstract void start();
  
      public abstract void stop();
  
      /**
       * {@inheritDoc}
       */
      @Override
      public boolean isPowerSaveMode() {
          return mPowerSaveMode;
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public boolean isNotPowerSaveMode() {
          return !isNotPowerSaving();
      }
  
      protected void setPowerSaveMode(boolean psm) {
          if (DEBUG_POWER_SAVING) psm = true;
          if (mPowerSaveMode == psm) return;
          sPowerSaveMode = mPowerSaveMode = psm;
          notifyListeners();
      }
  
      private void notifyListeners() {
          for (OnPowerSaveChanged listener : mListeners) {
              listener.onPowerSaveChanged(mPowerSaveMode);
          }
      }
  
      /**
       * @author Artem Chepurnoy
       */
      @TargetApi(Build.VERSION_CODES.LOLLIPOP)
      private static class PowerSaveLollipop extends PowerSaveDetector {
  
          private final PowerManager mPowerManager;
          private final BroadcastReceiver mReceiver =
                  new BroadcastReceiver() {
                      @Override
                      public void onReceive(Context context, Intent intent) {
                          switch (intent.getAction()) {
                              case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
                                  setPowerSaveMode(mPowerManager.isPowerSaveMode());
                                  break;
                          }
                      }
                  };
  
          @NonNull
          private final Atomic mAtomic = new Atomic(new Atomic.Callback() {
              @Override
              public void onStart(Object... objects) {
                  IntentFilter intentFilter = new IntentFilter();
                  intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
                  mContext.registerReceiver(mReceiver, intentFilter);
                  setPowerSaveMode(mPowerManager.isPowerSaveMode());
              }
  
              @Override
              public void onStop(Object... objects) {
                  mContext.unregisterReceiver(mReceiver);
              }
          });
  
          public PowerSaveLollipop(@NonNull Context context) {
              super(context);
              mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
          }
  
          @Override
          public void start() {
              mAtomic.start();
          }
  
          @Override
          public void stop() {
              mAtomic.stop();
          }
      }
  
      /**
       * @author Artem Chepurnoy
       */
      private static class PowerSaveCompat extends PowerSaveDetector {
  
          public PowerSaveCompat(@NonNull Context context) {
              super(context);
          }
  
          @Override
          public void start() { /* empty */ }
  
          @Override
          public void stop() { /* empty */ }
  
      }
  
  }