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}