# How to Configure the Silent Period (Do Not Disturb) Time in SmsForwarder

> Learn how to configure the silent period Do Not Disturb time in SmsForwarder. Understand how start and end times are stored and enforced for uninterrupted messaging.

- Repository: [pppscn/SmsForwarder](https://github.com/pppscn/SmsForwarder)
- Tags: how-to-guide
- Published: 2026-06-22

---

**SmsForwarder stores silent period hours as integers (0-23) in SharedPreferences via `SettingUtils`, enforces them in `SendWorker` and `SendUtils`, and disables the feature when start and end times are equal.**

SmsForwarder implements a configurable silent period—also known as Do Not Disturb (DND)—that blocks message forwarding during user-defined hours. This feature operates at both global and per-rule levels, utilizing a three-layer architecture spanning UI components, SharedPreferences storage, and background worker enforcement. Understanding how these components interact ensures reliable suppression of unwanted notifications during rest periods.

## Architecture Overview: Three Layers of Silent Period Management

The silent period implementation spans three distinct architectural layers in the SmsForwarder codebase. The **UI layer** collects input through time picker dialogs in [`SettingsFragment.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SettingsFragment.kt) and [`RulesEditFragment.kt`](https://github.com/pppscn/SmsForwarder/blob/main/RulesEditFragment.kt). The **persistence layer** stores values using SharedPreferences keys defined in [`Constants.kt`](https://github.com/pppscn/SmsForwarder/blob/main/Constants.kt) and accessed via delegated properties in [`SettingUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SettingUtils.kt). Finally, the **runtime layer** enforces restrictions in [`SendWorker.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SendWorker.kt) for global settings and [`SendUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SendUtils.kt) for rule-specific logic.

## Configuring Silent Period Hours in the User Interface

Users define the silent window by selecting start and end hours (0-23) through the application's settings interface, defined in [`app/src/main/res/layout/fragment_settings.xml`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/res/layout/fragment_settings.xml).

### Global Configuration in SettingsFragment

In [`app/src/main/kotlin/cn/ppps/forwarder/fragment/SettingsFragment.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/fragment/SettingsFragment.kt), the `btn_silent_period` button triggers a `TimeOptionPicker` dialog. When users confirm their selection, the system writes the chosen indices to `SettingUtils` and updates the `tv_silent_period` TextView:

```kotlin
// From SettingsFragment.kt
R.id.btn_silent_period -> {
    TimeOptionPicker.Builder()
        .setTitleText(getString(R.string.select_time_period))
        .setSelectOptions(SettingUtils.silentPeriodStart, SettingUtils.silentPeriodEnd)
        .build<Any>()
        .also { picker -> picker.setOnOptionSelectListener { opt1, opt2 ->
            SettingUtils.silentPeriodStart = opt1
            SettingUtils.silentPeriodEnd   = opt2
            binding!!.tvSilentPeriod.text = "${mTimeOption[opt1]} ~ ${mTimeOption[opt2]}"
        } }
}

```

### Per-Rule Configuration

Individual forwarding rules can override global settings via [`RulesEditFragment.kt`](https://github.com/pppscn/SmsForwarder/blob/main/RulesEditFragment.kt), which stores values in the `Rule` entity database columns: `silent_period_start`, `silent_period_end`, and `silent_day_of_week`.

## Data Persistence with SharedPreferences

The application persists configuration using Android's SharedPreferences through a delegated property pattern in [`SettingUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SettingUtils.kt).

In [`app/src/main/kotlin/cn/ppps/forwarder/utils/Constants.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/utils/Constants.kt), the keys are defined as `SP_SILENT_PERIOD_START` and `SP_SILENT_PERIOD_END`. The `SettingUtils` object maps these to integer properties:

```kotlin
// From SettingUtils.kt
var silentPeriodStart: Int by SharedPreference(SP_SILENT_PERIOD_START, 0)
var silentPeriodEnd:   Int by SharedPreference(SP_SILENT_PERIOD_END, 0)

```

When `silentPeriodStart` equals `silentPeriodEnd`, the feature is effectively disabled, allowing messages to forward at any time.

## Runtime Enforcement in Workers

Forwarding workers validate the current time against the configured window before processing messages.

### Global Silent Period Check

In [`app/src/main/kotlin/cn/ppps/forwarder/workers/SendWorker.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/workers/SendWorker.kt), the worker retrieves stored hours and calls `DataProvider.isCurrentTimeInPeriod()`:

```kotlin
// From SendWorker.kt
Log.d(TAG, "silentPeriodStart = ${SettingUtils.silentPeriodStart}, silentPeriodEnd = ${SettingUtils.silentPeriodEnd}")
if (SettingUtils.silentPeriodStart != SettingUtils.silentPeriodEnd) {
    val isSilent = DataProvider.isCurrentTimeInPeriod(
        SettingUtils.silentPeriodStart, SettingUtils.silentPeriodEnd)
    if (isSilent) {
        updateLogs(logId, 0, getString(R.string.silent_time_period))
        return Result.success()
    }
}

```

### Per-Rule Validation

For rule-specific enforcement, [`SendUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SendUtils.kt) evaluates both the time window and an optional `silent_day_of_week` CSV field to restrict DND to specific weekdays.

## Understanding the Time Window Logic

The silent period supports two operational modes:

- **Standard Window**: When `end > start`, the period operates within the same calendar day (e.g., 09:00 to 17:00).
- **Midnight Spanning**: When `end < start`, the window crosses midnight (e.g., 22:00 to 06:00 covers 22:00-23:59 and 00:00-06:00).

The `DataProvider.isCurrentTimeInPeriod()` utility handles these calculations by comparing the current hour against the configured boundaries.

## Implementing Manual Silent Period Checks

Developers can replicate the enforcement logic using standard Calendar operations:

```kotlin
fun shouldForwardNow(): Boolean {
    val now = Calendar.getInstance()
    val hour = now.get(Calendar.HOUR_OF_DAY)

    val start = SettingUtils.silentPeriodStart
    val end   = SettingUtils.silentPeriodEnd

    // Disabled when times are equal
    if (start == end) return true

    return if (end > start) {
        hour < start || hour >= end      // Outside same-day window
    } else {
        hour < start && hour >= end      // Outside midnight-spanning window
    }
}

```

This implementation mirrors the logic found in [`SendWorker.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SendWorker.kt) and supports both standard and overnight configurations.

## Summary

- SmsForwarder implements silent period functionality through **UI components** in [`SettingsFragment.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SettingsFragment.kt) and [`RulesEditFragment.kt`](https://github.com/pppscn/SmsForwarder/blob/main/RulesEditFragment.kt) using `TimeOptionPicker` dialogs defined in [`fragment_settings.xml`](https://github.com/pppscn/SmsForwarder/blob/main/fragment_settings.xml).
- Configuration persists via **SharedPreferences** keys `SP_SILENT_PERIOD_START` and `SP_SILENT_PERIOD_END`, accessed through delegated properties in [`SettingUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SettingUtils.kt).
- **Runtime enforcement** occurs in [`SendWorker.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SendWorker.kt) and [`SendUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SendUtils.kt) using `DataProvider.isCurrentTimeInPeriod()` to validate the current hour against the stored window.
- The feature **disables automatically** when start and end times are identical, and supports **midnight-spanning windows** when the end time is less than the start time.
- Per-rule configurations can include **weekday restrictions** via the `silent_day_of_week` database column in the `Rule` entity.

## Frequently Asked Questions

### What happens when the silent period start and end times are the same?

When `silentPeriodStart` equals `silentPeriodEnd`, SmsForwarder interprets this as a disabled state and allows message forwarding at all hours. This check appears in [`SendWorker.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SendWorker.kt) before invoking the time validation logic, effectively bypassing the DND feature.

### How does SmsForwarder handle silent periods that cross midnight?

The `DataProvider.isCurrentTimeInPeriod()` method correctly handles overnight windows. When the end time is less than the start time (e.g., 22:00 to 06:00), the logic treats the period as spanning two calendar days, blocking forwarding from 22:00-23:59 and 00:00-06:00 while allowing it during 06:00-22:00.

### Can different forwarding rules have different silent periods?

Yes. While global settings apply to all messages by default, individual rules defined in [`Rule.kt`](https://github.com/pppscn/SmsForwarder/blob/main/Rule.kt) can specify custom `silent_period_start`, `silent_period_end`, and `silent_day_of_week` values. The [`SendUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SendUtils.kt) file evaluates these rule-specific settings independently during per-rule forwarding logic.

### Where are the silent period preference keys defined?

The SharedPreferences keys `SP_SILENT_PERIOD_START` and `SP_SILENT_PERIOD_END` are defined as constants in [`app/src/main/kotlin/cn/ppps/forwarder/utils/Constants.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/utils/Constants.kt) and consumed by the delegated properties in [`SettingUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SettingUtils.kt).