@Override
  public void onReceive(Context context, Intent intent) {
    LogHandler.configureLogger();

    try {
      String log = "onReceive: Action: ";
      log += intent.getAction();
      log += "( ";
      if (intent.getData() != null) {
        log += intent.getData().getScheme();
        log += "://";
        log += intent.getData().getHost();
      }
      log += " ) ";
      Bundle extras = intent.getExtras();
      log += "{ ";
      if (extras != null) {
        for (String extra : extras.keySet()) {
          log += extra + "[" + extras.get(extra) + "], ";
        }
      }
      log += " }";
      Log.d(this, log);
    } catch (Exception e) {
      Log.e(e);
    }

    try {
      if (ExternalAppConstants.SLEEP_AS_ANDROID_ALARM_EVENT
          .ALARM_TRIGGERED
          .getIntentAction()
          .equals(intent.getAction())) {
        Log.d("IntentReceiver", "Alarm triggered!");
        ActionHandler.execute(
            context, ExternalAppConstants.SLEEP_AS_ANDROID_ALARM_EVENT.ALARM_TRIGGERED);

      } else if (ExternalAppConstants.SLEEP_AS_ANDROID_ALARM_EVENT
          .ALARM_SNOOZED
          .getIntentAction()
          .equals(intent.getAction())) {
        Log.d("IntentReceiver", "Alarm snoozed...");
        ActionHandler.execute(
            context, ExternalAppConstants.SLEEP_AS_ANDROID_ALARM_EVENT.ALARM_SNOOZED);

      } else if (ExternalAppConstants.SLEEP_AS_ANDROID_ALARM_EVENT
          .ALARM_DISMISSED
          .getIntentAction()
          .equals(intent.getAction())) {
        Log.d("IntentReceiver", "Alarm dismissed...");
        ActionHandler.execute(
            context, ExternalAppConstants.SLEEP_AS_ANDROID_ALARM_EVENT.ALARM_DISMISSED);

      } else {
        Log.d("IntentReceiver", "Received unknown intent: " + intent.getAction());
      }

    } catch (Exception e) {
      Log.e(e);
    }
  }
  /**
   * Creates a new Backup
   *
   * @param useExternalStorage use external storage path instead of internal?
   * @param name name of backup
   * @param force overwrite existing folders?
   * @throws CreateBackupException
   * @throws BackupAlreadyExistsException
   */
  public void createBackup(boolean useExternalStorage, @NonNull String name, boolean force)
      throws CreateBackupException, BackupAlreadyExistsException {
    if (useExternalStorage) {
      // TODO: kp wie man internen und externen speicher unterscheidet
    } else {
      File src;
      File dst;

      dst = new File(SmartphonePreferencesHandler.getBackupPath() + File.separator + name);
      if (!dst.exists()) {
        dst.mkdirs();
      } else {
        if (force) {
          // remove existing backup
          try {
            if (!deleteRecursive(dst)) {
              throw new CreateBackupException("Error deleting existing Backup");
            }
          } catch (Exception e) {
            Log.e(e);
            throw new CreateBackupException(e);
          }
          dst.mkdirs();
        } else {
          throw new BackupAlreadyExistsException();
        }
      }

      try {
        // copy database
        src = new File(context.getFilesDir().getParent() + File.separator + "databases");
        dst =
            new File(
                SmartphonePreferencesHandler.getBackupPath()
                    + File.separator
                    + name
                    + File.separator
                    + "databases");
        if (src.exists()) {
          copyDirectory(src, dst);
        }

        // copy preferences
        src = new File(context.getFilesDir().getParent() + File.separator + "shared_prefs");
        dst =
            new File(
                SmartphonePreferencesHandler.getBackupPath()
                    + File.separator
                    + name
                    + File.separator
                    + "shared_prefs");
        if (src.exists()) {
          copyDirectory(src, dst);
        }
      } catch (Exception e) {
        Log.e(e);
        throw new CreateBackupException(e);
      }
    }
  }
  private void parseActionIntent(Context context, Intent intent) {
    try {
      long id = Long.valueOf(intent.getData().getHost());
      Timer timer = DatabaseHandler.getTimer(id);

      Calendar currentTime = Calendar.getInstance();
      if (Build.VERSION.SDK_INT < 19) {
        int currentHour = currentTime.get(Calendar.HOUR_OF_DAY);
        int executionHour = timer.getExecutionTime().get(Calendar.HOUR_OF_DAY);
        if (currentHour != executionHour) {
          Log.d(
              this,
              "Timer hour doesnt match: "
                  + currentHour
                  + " != "
                  + timer.getExecutionTime().get(Calendar.HOUR_OF_DAY));
          return;
        }

        int currentMinute = currentTime.get(Calendar.MINUTE);
        int executionMinute = timer.getExecutionTime().get(Calendar.MINUTE);
        if (!(currentMinute >= executionMinute && currentMinute <= executionMinute + 3)) {
          Log.d(
              this,
              "Timer minute not in valid range: currentMinute: "
                  + currentMinute
                  + " ; executionMinute: "
                  + executionMinute);
          return;
        }
      }

      Log.d(this, "executing timer...");
      switch (timer.getExecutionType()) {
        case Timer.EXECUTION_TYPE_WEEKDAY:
          WeekdayTimer weekdayTimer = (WeekdayTimer) timer;

          if (weekdayTimer.containsExecutionDay(currentTime.get(Calendar.DAY_OF_WEEK))) {
            ActionHandler.execute(context, timer);
          } else {
            Log.d(this, "timer executionDays doesn't contain current day, not executing timer");
          }
          break;
        case Timer.EXECUTION_TYPE_INTERVAL:
          ActionHandler.execute(context, timer);
          break;
        default:
          Log.e(this, "Unknown Timer executionType: " + timer.getExecutionType());
          break;
      }

    } catch (Exception e) {
      StatusMessageHandler.showErrorMessage(context, e);
    }

    reinitializeAlarms(context);
  }
  @Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    Log.d("Updating Room Widgets...");
    // Perform this loop procedure for each App Widget that belongs to this provider
    for (int i = 0; i < appWidgetIds.length; i++) {
      int appWidgetId = appWidgetIds[i];
      RemoteViews remoteViews =
          new RemoteViews(
              context.getResources().getString(eu.power_switch.shared.R.string.PACKAGE_NAME),
              R.layout.widget_room);

      try {
        RoomWidget roomWidget = DatabaseHandler.getRoomWidget(appWidgetId);
        Room room = DatabaseHandler.getRoom(roomWidget.getRoomId());
        if (room != null) {
          Apartment apartment = DatabaseHandler.getApartment(room.getApartmentId());

          // update UI
          remoteViews.setTextViewText(
              R.id.textView_room_widget_name, apartment.getName() + ": " + room.getName());

          // set button action
          remoteViews.setOnClickPendingIntent(
              R.id.button_on,
              WidgetIntentReceiver.buildRoomWidgetButtonPendingIntent(
                  context,
                  apartment,
                  room,
                  context.getString(R.string.on),
                  ConfigureRoomWidgetActivity.ROOM_INTENT_ID_OFFSET + appWidgetId));
          remoteViews.setOnClickPendingIntent(
              R.id.button_off,
              WidgetIntentReceiver.buildRoomWidgetButtonPendingIntent(
                  context,
                  apartment,
                  room,
                  context.getString(R.string.off),
                  ConfigureRoomWidgetActivity.ROOM_INTENT_ID_OFFSET + appWidgetId + 1));
          remoteViews.setViewVisibility(R.id.linearlayout_room_widget, View.VISIBLE);
        } else {
          remoteViews.setTextViewText(
              R.id.textView_room_widget_name, context.getString(R.string.room_not_found));
          remoteViews.setViewVisibility(R.id.linearlayout_room_widget, View.GONE);
        }
      } catch (Exception e) {
        Log.e(e);
        remoteViews.setTextViewText(
            R.id.textView_room_widget_name, context.getString(R.string.unknown_error));
        remoteViews.setViewVisibility(R.id.linearlayout_room_widget, View.GONE);
      }
      appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
    }
    super.onUpdate(context, appWidgetManager, appWidgetIds);
  }
 @Override
 public void onDeleted(Context context, int[] appWidgetIds) {
   Log.d("Deleting Room Widgets: " + Arrays.toString(appWidgetIds));
   for (int appWidgetId : appWidgetIds) {
     try {
       DatabaseHandler.deleteRoomWidget(appWidgetId);
     } catch (Exception e) {
       Log.e(e);
     }
   }
   super.onDeleted(context, appWidgetIds);
 }
  /**
   * Restore Backup
   *
   * @param name name of backup
   * @throws BackupNotFoundException
   * @throws RestoreBackupException
   */
  public void restoreBackup(@NonNull String name)
      throws BackupNotFoundException, RestoreBackupException {
    // create source path object
    File src = new File(SmartphonePreferencesHandler.getBackupPath() + File.separator + name);
    if (src.exists()) {
      try {
        // create destination path object
        File dst = new File(context.getFilesDir().getParent());

        // delete existing files
        for (File fileOrFolder : dst.listFiles()) {
          if (fileOrFolder
                  .getPath()
                  .equals(context.getFilesDir().getParent() + File.separator + "shared_prefs")
              || fileOrFolder
                  .getPath()
                  .equals(context.getFilesDir().getParent() + File.separator + "databases")) {
            deleteRecursive(fileOrFolder);
          }
        }
        // copy directory to system folder
        copyDirectory(src, dst);
      } catch (Exception e) {
        Log.e(e);
        throw new RestoreBackupException(e);
      }
    } else {
      throw new BackupNotFoundException();
    }
  }
  @Override
  public void onReceive(Context context, Intent intent) {
    LogHandler.configureLogger();

    Log.d(this, intent);

    try {
      if (intent.getAction().equals(TimerConstants.TIMER_ACTIVATION_INTENT)) {
        Log.d(this, "parsing timer activation intent...");
        parseActionIntent(context, intent);
      } else if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
        // restart all active alarms because device rebooted
        Log.d(this, "restarting all active alarms because device rebooted...");
        reinitializeAlarms(context);
      } else {
        Log.d(this, "Received unknown intent: " + intent.getAction());
      }
    } catch (Exception e) {
      Log.e(e);
    }
  }
 /**
  * Remove a Backup
  *
  * @param name name of backup
  * @throws BackupNotFoundException
  * @throws RemoveBackupException
  */
 public void removeBackup(@NonNull String name)
     throws BackupNotFoundException, RemoveBackupException {
   try {
     File backupFolder =
         new File(SmartphonePreferencesHandler.getBackupPath() + File.separator + name);
     if (!backupFolder.exists()) {
       throw new BackupNotFoundException();
     }
     deleteRecursive(backupFolder);
   } catch (Exception e) {
     Log.e(e);
     throw new RemoveBackupException(e);
   }
 }
  @Override
  public String getSignal(Gateway gateway, String action)
      throws GatewayNotSupportedException, ActionNotSupportedException {
    boolean actionSupported = false;
    for (Button button : buttons) {
      if (button.getName().equals(action)) {
        actionSupported = true;
        break;
      }
    }
    if (!actionSupported) {
      throw new ActionNotSupportedException(action);
    }

    String lo = "1,";
    String hi = "3,";
    String seqHi = hi + lo + hi + lo;
    String seqLo = lo + hi + lo + hi;
    String seqFl = lo + hi + hi + lo;
    String h = seqFl;
    String l = seqHi;
    String on = seqFl + seqFl;
    String off = seqLo + seqLo;
    String additional = seqLo + seqFl + seqFl;

    // switch channelMaster (character)
    String master = "";
    switch (channelMaster) {
      case 'A':
        master = l + h + h + h;
        break;
      case 'B':
        master = h + l + h + h;
        break;
      case 'C':
        master = h + h + l + h;
        break;
      case 'D':
        master = h + h + h + l;
        break;
      default:
        Log.e("Switch", "No Matching Master");
        break;
    }

    // switch channelSlave (number)
    String slave = "";
    switch (channelSlave) {
      case 1:
        slave = l + h + h;
        break;
      case 2:
        slave = h + l + h;
        break;
      case 3:
        slave = h + h + l;
        break;
      default:
        Log.e("Switch", "No Matching Slave");
        break;
    }

    if (gateway instanceof ConnAir) {
      if (action.equals(context.getString(R.string.on))) {
        String ON = headConnAir + master + slave + additional + on + tailConnAir;
        return ON;
      } else {
        String OFF = headConnAir + master + slave + additional + off + tailConnAir;
        return OFF;
      }
    } else if (gateway instanceof BrematicGWY433) {
      if (action.equals(context.getString(R.string.on))) {
        String ON = headConnAir + master + slave + additional + on + tailConnAir;
        return ON;
      } else {
        String OFF = headConnAir + master + slave + additional + off + tailConnAir;
        return OFF;
      }
    } else if (gateway instanceof ITGW433) {
      if (action.equals(context.getString(R.string.on))) {
        String ON = headITGW + master + slave + additional + on + tailITGW;
        return ON;
      } else {
        String OFF = headITGW + master + slave + additional + off + tailITGW;
        return OFF;
      }
    } else {
      throw new GatewayNotSupportedException();
    }
  }