Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 4 additions & 6 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ plugins {

android {
namespace = "com.example.gisingv3"
compileSdk {
version = release(36)
}
compileSdk = 36

defaultConfig {
applicationId = "com.example.gisingv3"
minSdk = 24
targetSdk = 36
versionCode = 1
versionName = "1.0"
versionCode = 41
versionName = "4.1"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
Expand All @@ -36,7 +34,7 @@ android {
dependencies {
implementation(libs.appcompat)
implementation(libs.material)
implementation("com.google.code.gson:gson:2.10.1") // Added GSON for JSON serialization
implementation("com.google.code.gson:gson:2.10.1")
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
Expand Down
Binary file modified app/release/baselineProfiles/0/app-release.dm
Binary file not shown.
Binary file modified app/release/baselineProfiles/1/app-release.dm
Binary file not shown.
4 changes: 2 additions & 2 deletions app/release/output-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"versionCode": 41,
"versionName": "4.1",
"outputFile": "app-release.apk"
}
],
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

<application
android:allowBackup="true"
Expand Down Expand Up @@ -40,6 +41,7 @@
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>

Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/com/example/gisingv3/AddAlarmActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ private void updateTimeDisplay() {
String amPm = selectedHour >= 12 ? "PM" : "AM";
int hour12 = selectedHour % 12;
if (hour12 == 0) hour12 = 12;
tvTimeInput.setText(String.format(Locale.getDefault(), "%02d:%02d %s", hour12, selectedMinute, amPm));
// Use %d instead of %02d for hour to remove leading zero
tvTimeInput.setText(String.format(Locale.getDefault(), "%d:%02d %s", hour12, selectedMinute, amPm));
}

private void updateDaySelection(int index) {
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/example/gisingv3/Alarm.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public Alarm(int id, int hour, int minute, String challengeType, int difficultyL
public boolean isEnabled() { return isEnabled; }
public void setEnabled(boolean enabled) { isEnabled = enabled; }
public boolean[] getDaysSelected() {
// Safety check for older saved data
if (daysSelected == null) return new boolean[7];
return daysSelected;
}
Expand All @@ -39,7 +38,8 @@ public String getTimeString() {
String amPm = hour >= 12 ? "PM" : "AM";
int hour12 = hour % 12;
if (hour12 == 0) hour12 = 12;
return String.format(Locale.getDefault(), "%02d:%02d %s", hour12, minute, amPm);
// Use %d instead of %02d for hour to remove the leading zero
return String.format(Locale.getDefault(), "%d:%02d %s", hour12, minute, amPm);
}

public String getDaysDisplay() {
Expand Down
31 changes: 12 additions & 19 deletions app/src/main/java/com/example/gisingv3/AlarmReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import androidx.core.app.NotificationCompat;
import java.util.Calendar;
import java.util.List;
Expand All @@ -20,15 +21,19 @@ public class AlarmReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
// Use a WakeLock to ensure the CPU stays awake while we process the alarm
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GisingApp:AlarmWakeLock");
wakeLock.acquire(10000); // Hold for 10 seconds

Comment on lines +24 to +28

Copilot AI Mar 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PowerManager can be null here, and the WakeLock is never released. This can crash (NullPointerException) and/or keep the CPU awake longer than necessary if later code throws. Add a null-check for powerManager, and wrap the receiver work in try/finally to release() the wake lock (still keeping a timeout as a safety net).

Copilot uses AI. Check for mistakes.
int alarmId = intent.getIntExtra("alarm_id", -1);
String challengeType = intent.getStringExtra("challenge_type");
int difficulty = intent.getIntExtra("difficulty", 1);

createNotificationChannel(context);

// Prepare the ring activity intent
Intent ringIntent = new Intent(context, AlarmRingActivity.class);
ringIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
ringIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
ringIntent.putExtra("alarm_id", alarmId);
ringIntent.putExtra("challenge_type", challengeType);
ringIntent.putExtra("difficulty", difficulty);
Expand All @@ -55,14 +60,13 @@ public void onReceive(Context context, Intent intent) {

NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
// Use unique alarmId to allow multiple simultaneous alarms
notificationManager.notify(alarmId, builder.build());
}

// Start activity
// Force the activity to the front
context.startActivity(ringIntent);

// Reschedule for next occurrence if it's a repeating alarm
// Reschedule logic
rescheduleNextOccurrence(context, alarmId);
}

Expand All @@ -72,10 +76,8 @@ private void rescheduleNextOccurrence(Context context, int alarmId) {

for (Alarm alarm : alarmList) {
if (alarm.getId() == alarmId && alarm.isEnabled()) {
// If it's a repeating alarm, calculate and schedule the next time
boolean hasDays = false;
for (boolean d : alarm.getDaysSelected()) if (d) hasDays = true;

if (hasDays) {
scheduleNext(context, alarm);
}
Expand All @@ -95,24 +97,19 @@ private void scheduleNext(Context context, Alarm alarm) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, alarm.getId(), intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

// Logic to find next trigger time (similar to MainActivity)
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, alarm.getHour());
calendar.set(Calendar.MINUTE, alarm.getMinute());
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);

long now = System.currentTimeMillis();
boolean[] days = alarm.getDaysSelected();

// Start looking from "tomorrow" relative to the current alarm trigger
calendar.add(Calendar.DAY_OF_YEAR, 1);

for (int i = 0; i < 7; i++) {
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
int dayIndex = dayOfWeek - 1;

if (days[dayIndex]) {
if (alarm.getDaysSelected()[dayIndex]) {
if (alarmManager != null) {
Comment on lines 108 to 113

Copilot AI Mar 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop calls alarm.getDaysSelected() on every iteration. If daysSelected is null, getDaysSelected() allocates a new boolean[7] each time, and even when non-null it’s repeated work. Store the result in a local boolean[] days = alarm.getDaysSelected() before the loop and index into that array.

Copilot uses AI. Check for mistakes.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (alarmManager.canScheduleExactAlarms()) {
Expand Down Expand Up @@ -148,17 +145,13 @@ private void createNotificationChannel(Context context) {
.build();

Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
if (alarmSound == null) {
alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
}
if (alarmSound == null) alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);

channel.setSound(alarmSound, audioAttributes);
channel.enableVibration(true);
channel.setLockscreenVisibility(android.app.Notification.VISIBILITY_PUBLIC);

if (manager != null) {
manager.createNotificationChannel(channel);
}
if (manager != null) manager.createNotificationChannel(channel);
}
}
}
Loading
Loading