001// SPDX-License-Identifier: GPL-3.0-or-later
002// Copyright © 2026 Aurélien Pierre
003
004package com.aurelienpierre.sioul;
005
006import android.app.Activity;
007import android.os.Bundle;
008import android.util.TypedValue;
009import android.view.Gravity;
010import android.view.View;
011import android.view.WindowManager;
012import android.widget.Button;
013import android.widget.LinearLayout;
014import android.widget.TextClock;
015
016import java.lang.ref.WeakReference;
017
018/**
019 * The alarm at waking, over the lock screen (WakeRinger's full-screen
020 * notification): the time, Stop, 10 min later (a try's last ring: Stop
021 * alone). Nothing else. Back does not end it: the alarm rings until one of
022 * the two. Dark, the screen kept on while it shows. Opened once the ring is
023 * over (from an old notification), it closes at once.
024 */
025public final class WakeScreen extends Activity
026{
027    private static WeakReference<WakeScreen> shown = new WeakReference<>(null);
028
029    /** The ring is over (here, from its notification, or 10 min later): the screen goes. */
030    static void close()
031    {
032        WakeScreen screen = shown.get();
033        if (screen != null)
034            screen.runOnUiThread(screen::finish);
035    }
036
037    /** Another ring over the one shown (a waking over a try): its buttons as they are now. */
038    static void refresh()
039    {
040        WakeScreen screen = shown.get();
041        if (screen != null)
042            screen.runOnUiThread(() -> screen.setContentView(screen.layout()));
043    }
044
045    @Override
046    protected void onCreate(Bundle state)
047    {
048        super.onCreate(state);
049        if (!WakeRinger.ringing()) {
050            finish();
051            return;
052        }
053        shown = new WeakReference<>(this);
054        setShowWhenLocked(true);
055        setTurnScreenOn(true);
056        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
057        setContentView(layout());
058    }
059
060    private View layout()
061    {
062        final float dp = getResources().getDisplayMetrics().density;
063        LinearLayout column = new LinearLayout(this);
064        column.setOrientation(LinearLayout.VERTICAL);
065        column.setGravity(Gravity.CENTER);
066        column.setBackgroundColor(0xFF101412);
067        int margin = (int) (24 * dp);
068        column.setPadding(margin, margin, margin, margin);
069        // The time now, as the phone writes it, kept up to date.
070        TextClock time = new TextClock(this);
071        time.setTextSize(TypedValue.COMPLEX_UNIT_SP, 64);
072        time.setTextColor(0xFFE6EAE7);
073        time.setGravity(Gravity.CENTER);
074        column.addView(time, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
075        column.addView(button(WakeAlarms.word(this, "stop"), false, dp), spaced(48, dp));
076        if (WakeRinger.laterOffered())
077            column.addView(button(WakeAlarms.word(this, "later"), true, dp), spaced(16, dp));
078        return column;
079    }
080
081    private Button button(String text, boolean later, float dp)
082    {
083        Button button = new Button(this);
084        button.setText(text);
085        button.setAllCaps(false);
086        button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
087        button.setMinHeight((int) (64 * dp));
088        button.setOnClickListener(v -> {
089            WakeRinger.stop(getApplicationContext(), later, WakeRinger.trying());
090            finish();
091        });
092        return button;
093    }
094
095    private static LinearLayout.LayoutParams spaced(int above, float dp)
096    {
097        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
098        params.topMargin = (int) (above * dp);
099        return params;
100    }
101
102    @Override
103    public void onBackPressed()
104    {
105        // The alarm rings until Stop or 10 min later: Back does not end it.
106    }
107
108    @Override
109    protected void onDestroy()
110    {
111        if (shown.get() == this)
112            shown.clear();
113        super.onDestroy();
114    }
115}