Før jeg spurte aistudio
This commit is contained in:
parent
d9d128245c
commit
6f3fd9059d
9 changed files with 520 additions and 250 deletions
|
|
@ -16,6 +16,11 @@ android {
|
|||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
// NYTT: Dette må til for å kunne bruke BuildConfig.DEBUG i koden
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
|
|
@ -26,7 +31,6 @@ android {
|
|||
}
|
||||
}
|
||||
compileOptions {
|
||||
// ENDRET: Oppgradert til Java 11 for å fikse build warnings
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,15 @@
|
|||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<application
|
||||
android:name=".KbsApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
|
|
@ -30,7 +34,8 @@
|
|||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.KBSIntranett">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
|
@ -39,7 +44,10 @@
|
|||
|
||||
<activity android:name=".WebViewActivity" />
|
||||
|
||||
<receiver android:name=".AlarmReceiver" android:exported="false" />
|
||||
<receiver
|
||||
android:name=".AlarmReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
|
|
|||
|
|
@ -1,19 +1,22 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
public class AlarmReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "KBS_DEBUG";
|
||||
private static final String CHANNEL_ID = "kbs_calendar_channel";
|
||||
private static final String CHANNEL_NAME = "KBS Kalendervarsler";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
|
@ -21,45 +24,51 @@ public class AlarmReceiver extends BroadcastReceiver {
|
|||
String message = intent.getStringExtra("MESSAGE");
|
||||
int notificationId = intent.getIntExtra("ID", 0);
|
||||
|
||||
Log.i(TAG, "AlarmReceiver: WAKE UP! Mottok alarm for: " + title);
|
||||
|
||||
createNotificationChannel(context);
|
||||
showNotification(context, title, message, notificationId);
|
||||
}
|
||||
|
||||
private void showNotification(Context context, String title, String message, int notificationId) {
|
||||
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "KBS Kalender", NotificationManager.IMPORTANCE_HIGH);
|
||||
channel.setDescription("Varsler for kalenderhendelser");
|
||||
manager.createNotificationChannel(channel);
|
||||
// Sjekk rettigheter for Android 13+
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
// Vi kan ikke vise varsel uten rettighet.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Intent openAppIntent = new Intent(context, MainActivity.class);
|
||||
openAppIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
// Intent for hva som skjer når man trykker på varselet (åpne appen)
|
||||
Intent tapIntent = new Intent(context, MainActivity.class);
|
||||
tapIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
openAppIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
|
||||
tapIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setSmallIcon(R.drawable.ic_launcher_foreground) // Pass på at du har et ikon her, ellers bruk R.mipmap.ic_launcher
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setCategory(NotificationCompat.CATEGORY_EVENT)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true);
|
||||
|
||||
try {
|
||||
manager.notify(notificationId, builder.build());
|
||||
Log.d(TAG, "AlarmReceiver: Varsel sendt til systemet.");
|
||||
} catch (SecurityException e) {
|
||||
Log.e(TAG, "AlarmReceiver: Feil - Mangler tillatelse til å sende varsel!", e);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "AlarmReceiver: Ukjent feil ved visning av varsel", e);
|
||||
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
notificationManager.notify(notificationId, builder.build());
|
||||
}
|
||||
|
||||
private void createNotificationChannel(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
int importance = NotificationManager.IMPORTANCE_HIGH;
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance);
|
||||
channel.setDescription("Varsler for kalenderhendelser i KBS Intranett");
|
||||
|
||||
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||
if (notificationManager != null) {
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.provider.CalendarContract;
|
||||
import android.util.Log;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -17,12 +18,10 @@ public class CalendarManager {
|
|||
|
||||
// --- KONFIGURASJON FOR GOOGLE DIREKTE-KOBLING ---
|
||||
private static final String GOOGLE_CALENDAR_ID = "kbservice.no_o2bmp5f9f540vedveit51optfo@group.calendar.google.com";
|
||||
|
||||
// TODO: Sett inn din API-nøkkel her!
|
||||
private static final String GOOGLE_API_KEY = "AIzaSyCos8VW5mClUcuhs86gbSJo8uitY0fVPus";
|
||||
|
||||
public static String getGoogleCalendarUrl() {
|
||||
// Hent hendelser fra 1 år tilbake i tid
|
||||
long oneYearAgo = System.currentTimeMillis() - (365L * 24 * 60 * 60 * 1000);
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
|
@ -34,10 +33,9 @@ public class CalendarManager {
|
|||
+ "&singleEvents=true"
|
||||
+ "&orderBy=startTime"
|
||||
+ "&maxResults=250"
|
||||
+ "&timeMin=" + timeMin; // URL-encoded er ikke nødvendig her siden Retrofit/OkHttp håndterer det, men timeMin bør være formatert
|
||||
+ "&timeMin=" + timeMin;
|
||||
}
|
||||
|
||||
// Konverterer Google Response til vår interne CalendarEvent
|
||||
public static List<CalendarEvent> convertGoogleResponse(GoogleCalendarModels.Response response) {
|
||||
List<CalendarEvent> events = new ArrayList<>();
|
||||
if (response == null || response.items == null) return events;
|
||||
|
|
@ -53,50 +51,69 @@ public class CalendarManager {
|
|||
|
||||
if (item.start != null) {
|
||||
if (item.start.dateTime != null) start = item.start.dateTime;
|
||||
else start = item.start.date; // Heldags
|
||||
else start = item.start.date;
|
||||
}
|
||||
if (item.end != null) {
|
||||
if (item.end.dateTime != null) end = item.end.dateTime;
|
||||
else end = item.end.date; // Heldags
|
||||
else end = item.end.date;
|
||||
}
|
||||
|
||||
// Varslings-logikk (Henter de sanne innstillingene)
|
||||
// --- SPY LOGGING (Se i Logcat etter KBS_DEBUG) ---
|
||||
if (title.toLowerCase().contains("test")) {
|
||||
Log.d("KBS_DEBUG", "--------------------------------------------------");
|
||||
Log.d("KBS_DEBUG", "ANALYSERER EVENT: " + title);
|
||||
Log.d("KBS_DEBUG", " Starttid: " + start);
|
||||
|
||||
if (item.reminders != null) {
|
||||
Log.d("KBS_DEBUG", " useDefault: " + item.reminders.useDefault);
|
||||
|
||||
if (item.reminders.overrides != null && !item.reminders.overrides.isEmpty()) {
|
||||
Log.d("KBS_DEBUG", " Fant " + item.reminders.overrides.size() + " overstyringer:");
|
||||
for (GoogleCalendarModels.Override override : item.reminders.overrides) {
|
||||
Log.d("KBS_DEBUG", " -> Metode: '" + override.method + "', Minutter: " + override.minutes);
|
||||
}
|
||||
} else {
|
||||
Log.d("KBS_DEBUG", " Ingen 'overrides' (spesifikke varsler) funnet i listen fra Google.");
|
||||
}
|
||||
} else {
|
||||
Log.d("KBS_DEBUG", " Ingen 'reminders'-seksjon funnet i JSON-responsen.");
|
||||
}
|
||||
Log.d("KBS_DEBUG", "--------------------------------------------------");
|
||||
}
|
||||
// -------------------------------------------------
|
||||
|
||||
// Varslings-logikk
|
||||
int reminderMinutes = 15; // Default fallback
|
||||
|
||||
if (item.reminders != null) {
|
||||
if (item.reminders.useDefault) {
|
||||
reminderMinutes = 15; // Standard i Google er ofte 10 eller 15, vi antar 15
|
||||
} else if (item.reminders.overrides != null) {
|
||||
for (GoogleCalendarModels.Override override : item.reminders.overrides) {
|
||||
if ("popup".equalsIgnoreCase(override.method) || "alert".equalsIgnoreCase(override.method)) {
|
||||
reminderMinutes = override.minutes;
|
||||
break; // Bruk den første popup-varslingen vi finner
|
||||
}
|
||||
}
|
||||
reminderMinutes = 15;
|
||||
} else if (item.reminders.overrides != null && !item.reminders.overrides.isEmpty()) {
|
||||
// Vi tar den første vi finner for å se om det fanger opp dine 10/26 minutter
|
||||
reminderMinutes = item.reminders.overrides.get(0).minutes;
|
||||
}
|
||||
}
|
||||
|
||||
CalendarEvent event = new CalendarEvent(title, start, end, desc, loc);
|
||||
event.setReminderMinutes(reminderMinutes);
|
||||
|
||||
// Formatér for UI med en gang
|
||||
formatEventForUI(event);
|
||||
|
||||
events.add(event);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
// --- EKSISTERENDE KODE (UENDRET UNDER) ---
|
||||
// --- RESTERENDE KODE (UENDRET) ---
|
||||
|
||||
// NY HJELPEMETODE: Finner ID-ene til kalendere som tilhører @kbs.no
|
||||
private static List<String> getKbsCalendarIds(Context context) {
|
||||
List<String> ids = new ArrayList<>();
|
||||
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
|
||||
return ids;
|
||||
}
|
||||
String[] projection = new String[] {
|
||||
CalendarContract.Calendars._ID,
|
||||
CalendarContract.Calendars.ACCOUNT_NAME
|
||||
};
|
||||
// Vi ser etter kontoer som slutter på @kbs.no
|
||||
// (SQL: account_name LIKE '%@kbs.no')
|
||||
String selection = CalendarContract.Calendars.ACCOUNT_NAME + " LIKE ?";
|
||||
String[] selectionArgs = new String[] {"%@kbs.no"};
|
||||
|
||||
|
|
@ -110,7 +127,6 @@ public class CalendarManager {
|
|||
if (cursor != null) {
|
||||
while (cursor.moveToNext()) {
|
||||
ids.add(cursor.getString(0));
|
||||
// Legg til kalender-ID
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
@ -126,17 +142,15 @@ public class CalendarManager {
|
|||
return deviceEvents;
|
||||
}
|
||||
|
||||
// 1. Finn først ID-ene til KBS-kalenderne
|
||||
List<String> kbsCalendarIds = getKbsCalendarIds(context);
|
||||
// Hvis ingen kbs-kalendere finnes på telefonen, returner tom liste
|
||||
if (kbsCalendarIds.isEmpty()) {
|
||||
return deviceEvents;
|
||||
}
|
||||
|
||||
// Hent events fra 1 år tilbake og 1 år frem
|
||||
long now = System.currentTimeMillis();
|
||||
long startMillis = now - (365L * 24 * 60 * 60 * 1000);
|
||||
long endMillis = now + (365L * 24 * 60 * 60 * 1000);
|
||||
|
||||
String[] projection = new String[]{
|
||||
CalendarContract.Events.TITLE,
|
||||
CalendarContract.Events.DTSTART,
|
||||
|
|
@ -146,8 +160,6 @@ public class CalendarManager {
|
|||
CalendarContract.Events.ALL_DAY
|
||||
};
|
||||
|
||||
// 2. Bygg opp spørringen for å filtrere på disse ID-ene
|
||||
// Resultatet blir noe sånt som: "((calendar_id = ?) OR (calendar_id = ?)) AND dtstart >= ? AND dtstart <= ?"
|
||||
StringBuilder selection = new StringBuilder("(");
|
||||
List<String> selectionArgsList = new ArrayList<>();
|
||||
|
||||
|
|
@ -166,6 +178,7 @@ public class CalendarManager {
|
|||
selectionArgsList.add(String.valueOf(endMillis));
|
||||
|
||||
String[] selectionArgs = selectionArgsList.toArray(new String[0]);
|
||||
|
||||
try (Cursor cursor = context.getContentResolver().query(
|
||||
CalendarContract.Events.CONTENT_URI,
|
||||
projection,
|
||||
|
|
@ -182,6 +195,7 @@ public class CalendarManager {
|
|||
String desc = cursor.getString(3);
|
||||
String loc = cursor.getString(4);
|
||||
int allDay = cursor.getInt(5);
|
||||
|
||||
String rawStart;
|
||||
String rawEnd;
|
||||
|
||||
|
|
@ -207,9 +221,11 @@ public class CalendarManager {
|
|||
|
||||
public static void formatEventForUI(CalendarEvent event) {
|
||||
if (event.getRawDate() == null) return;
|
||||
|
||||
SimpleDateFormat outputDay = new SimpleDateFormat("dd", Locale.getDefault());
|
||||
SimpleDateFormat outputMonth = new SimpleDateFormat("MMM", new Locale("no", "NO"));
|
||||
SimpleDateFormat outputTime = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
|
||||
outputMonth.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
outputTime.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
|
||||
|
|
@ -219,6 +235,7 @@ public class CalendarManager {
|
|||
boolean isAllDay = false;
|
||||
|
||||
String raw = event.getRawDate();
|
||||
|
||||
if (raw.length() == 10 && !raw.contains("T") && !raw.contains(" ")) {
|
||||
SimpleDateFormat shortFmt = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
date = shortFmt.parse(raw);
|
||||
|
|
@ -276,6 +293,7 @@ public class CalendarManager {
|
|||
String d2 = e2.getRawDate() != null ? e2.getRawDate() : "";
|
||||
return d1.compareTo(d2);
|
||||
});
|
||||
|
||||
return all;
|
||||
}
|
||||
}
|
||||
35
app/src/main/java/com/kbs/kbsintranett/KbsApplication.java
Normal file
35
app/src/main/java/com/kbs/kbsintranett/KbsApplication.java
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.os.Build;
|
||||
|
||||
public class KbsApplication extends Application {
|
||||
|
||||
public static final String CHANNEL_ID = "kbs_calendar_channel";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
createNotificationChannel();
|
||||
}
|
||||
|
||||
private void createNotificationChannel() {
|
||||
// Vi oppretter kanalen her ved oppstart, så den er klar uansett om
|
||||
// det er MainActivity eller en bakgrunnsjobb som trenger den.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
"KBS Kalendervarsler",
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
);
|
||||
channel.setDescription("Varsler for kalenderhendelser");
|
||||
|
||||
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||
if (manager != null) {
|
||||
manager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,13 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -11,11 +15,15 @@ import android.provider.Settings;
|
|||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.ExistingPeriodicWorkPolicy;
|
||||
import androidx.work.PeriodicWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignIn;
|
||||
|
|
@ -24,31 +32,42 @@ import com.google.android.gms.auth.api.signin.GoogleSignInClient;
|
|||
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
// VIKTIG: Erstatt denne med din Web Client ID
|
||||
// VIKTIG: Sørg for at denne matcher den du har i Google Cloud Console
|
||||
public static final String GOOGLE_WEB_CLIENT_ID = "738325360287-cidl3plnqv9ei74vm9vm5muustj6eenb.apps.googleusercontent.com";
|
||||
|
||||
private static final String TAG = "MainActivity";
|
||||
private NavController navController;
|
||||
private BottomNavigationView bottomNav;
|
||||
|
||||
// Launcher for å spørre om varslingstillatelse (Android 13+)
|
||||
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
// 1. Setup UI
|
||||
// --- 1. SETUP UI & NAVIGASJON ---
|
||||
// Sjekket activity_main.xml: ID er "bottom_nav_view"
|
||||
bottomNav = findViewById(R.id.bottom_nav_view);
|
||||
|
||||
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.nav_host_fragment);
|
||||
|
||||
if (navHostFragment != null) {
|
||||
navController = navHostFragment.getNavController();
|
||||
NavigationUI.setupWithNavController(bottomNav, navController);
|
||||
if (bottomNav != null) {
|
||||
NavigationUI.setupWithNavController(bottomNav, navController);
|
||||
}
|
||||
|
||||
// Skjul meny på login-skjerm
|
||||
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
|
||||
// Sjekker mot R.id.navigation_login som er ID'en til fragmentet
|
||||
if (bottomNav == null) return;
|
||||
|
||||
if (destination.getId() == R.id.navigation_login) {
|
||||
bottomNav.setVisibility(View.GONE);
|
||||
} else {
|
||||
|
|
@ -57,50 +76,32 @@ public class MainActivity extends AppCompatActivity {
|
|||
});
|
||||
}
|
||||
|
||||
// --- NYTT: Sjekk tillatelse for nøyaktige alarmer (Android 12+) ---
|
||||
// --- 2. VARSLINGSOPPSETT (NYTT) ---
|
||||
createNotificationChannel();
|
||||
|
||||
// Initialiser permission launcher for varsler
|
||||
requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
|
||||
if (isGranted) {
|
||||
Log.d(TAG, "Varslingstillatelse gitt!");
|
||||
} else {
|
||||
Log.e(TAG, "Varslingstillatelse avslått. Bruker får ikke kalendervarsler.");
|
||||
}
|
||||
});
|
||||
|
||||
// Sjekk tillatelser (både Varsler og Alarmer)
|
||||
checkNotificationPermission();
|
||||
checkExactAlarmPermission();
|
||||
|
||||
// 2. Start Silent Sign-In ved oppstart
|
||||
// Start bakgrunnsjobben for kalenderen
|
||||
scheduleCalendarWork();
|
||||
|
||||
// --- 3. AUTENTISERING (GAMMELT) ---
|
||||
checkLoginState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sjekker om appen har lov til å sette nøyaktige alarmer (SCHEDULE_EXACT_ALARM).
|
||||
* Hvis ikke, spør brukeren om å gå til innstillinger.
|
||||
* Sjekker om brukeren er logget inn med Google, og gjør en silent refresh mot WP.
|
||||
*/
|
||||
private void checkExactAlarmPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
if (alarmManager != null && !alarmManager.canScheduleExactAlarms()) {
|
||||
// Vi mangler tillatelse. Vis dialog.
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Varslingstillatelse kreves")
|
||||
.setMessage("For at kalenderen skal kunne varsle deg nøyaktig når et møte starter, må du gi appen tilgang til å sette alarmer.")
|
||||
.setPositiveButton("Gå til Innstillinger", (dialog, which) -> {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
|
||||
intent.setData(Uri.parse("package:" + getPackageName()));
|
||||
startActivity(intent);
|
||||
})
|
||||
.setNegativeButton("Senere", null)
|
||||
.show();
|
||||
} else {
|
||||
// Vi har tillatelse (eller er på eldre Android). Kjør logikk!
|
||||
runNotificationWorker();
|
||||
}
|
||||
} else {
|
||||
// Eldre Android-versjoner trenger ikke denne tillatelsen
|
||||
runNotificationWorker();
|
||||
}
|
||||
}
|
||||
|
||||
private void runNotificationWorker() {
|
||||
// --- DEBUG: TVING KJØRING AV KALENDER-SJEKK ---
|
||||
// Denne linjen kjører NotificationWorker umiddelbart ved oppstart for feilsøking.
|
||||
// Fjern eller kommenter ut denne når testingen er ferdig.
|
||||
WorkManager.getInstance(this).enqueue(OneTimeWorkRequest.from(NotificationWorker.class));
|
||||
// ----------------------------------------------
|
||||
}
|
||||
|
||||
private void checkLoginState() {
|
||||
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
|
||||
if (account == null) {
|
||||
|
|
@ -130,10 +131,8 @@ public class MainActivity extends AppCompatActivity {
|
|||
@Override
|
||||
public void onSuccess(String role) {
|
||||
Log.d(TAG, "Silent login fullført. Rolle: " + role);
|
||||
// Gå videre til Home hvis vi står på Login
|
||||
if (navController != null && navController.getCurrentDestination() != null &&
|
||||
navController.getCurrentDestination().getId() == R.id.navigation_login) {
|
||||
// Denne aksjonen finnes i mobile_navigation.xml
|
||||
navController.navigate(R.id.action_login_to_home);
|
||||
}
|
||||
}
|
||||
|
|
@ -155,11 +154,69 @@ public class MainActivity extends AppCompatActivity {
|
|||
private void navigateToLogin() {
|
||||
if (navController != null) {
|
||||
if (navController.getCurrentDestination() != null &&
|
||||
// Sjekker mot R.id.navigation_login som er ID'en til fragmentet
|
||||
navController.getCurrentDestination().getId() != R.id.navigation_login) {
|
||||
// Denne ID'en finnes i mobile_navigation.xml
|
||||
navController.navigate(R.id.navigation_login);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- NYE HJELPEMETODER FOR VARSLING ---
|
||||
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
CharSequence name = "KBS Kalendervarsler";
|
||||
String description = "Varsler for kalenderhendelser";
|
||||
int importance = NotificationManager.IMPORTANCE_HIGH;
|
||||
NotificationChannel channel = new NotificationChannel("kbs_calendar_channel", name, importance);
|
||||
channel.setDescription(description);
|
||||
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
||||
if (notificationManager != null) {
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNotificationPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sjekker om appen har lov til å sette nøyaktige alarmer (SCHEDULE_EXACT_ALARM).
|
||||
* Hvis ikke, spør brukeren om å gå til innstillinger.
|
||||
*/
|
||||
private void checkExactAlarmPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
if (alarmManager != null && !alarmManager.canScheduleExactAlarms()) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Varslingstillatelse kreves")
|
||||
.setMessage("For at kalenderen skal kunne varsle deg nøyaktig når et møte starter, må du gi appen tilgang til å sette alarmer.")
|
||||
.setPositiveButton("Gå til Innstillinger", (dialog, which) -> {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
|
||||
intent.setData(Uri.parse("package:" + getPackageName()));
|
||||
startActivity(intent);
|
||||
})
|
||||
.setNegativeButton("Senere", null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starter WorkManager som sjekker kalenderen hvert 15. minutt.
|
||||
*/
|
||||
private void scheduleCalendarWork() {
|
||||
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(NotificationWorker.class, 15, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
||||
"KbsCalendarWork",
|
||||
ExistingPeriodicWorkPolicy.UPDATE,
|
||||
workRequest
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,6 @@ public class NotificationWorker extends Worker {
|
|||
|
||||
try {
|
||||
String url = CalendarManager.getGoogleCalendarUrl();
|
||||
// Hent events synkront
|
||||
Response<GoogleCalendarModels.Response> response = RetrofitClient.getApiService().getDirectGoogleEvents(url).execute();
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
|
|
@ -52,32 +51,23 @@ public class NotificationWorker extends Worker {
|
|||
Context context = getApplicationContext();
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
// Sjekk rettigheter (Android 12+)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
if (!alarmManager.canScheduleExactAlarms()) {
|
||||
Log.e(TAG, "NotificationWorker: MANGLER fortsatt tillatelse! Gå til Innstillinger -> Apper -> KBS -> Alarmer og påminnelser.");
|
||||
Log.e(TAG, "NotificationWorker: MANGLER fortsatt tillatelse!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
// Bruker en parser som er litt mer fleksibel for datoer
|
||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
|
||||
int countSet = 0;
|
||||
|
||||
for (CalendarEvent event : events) {
|
||||
try {
|
||||
// Hopp over heldagshendelser (dato uten klokkeslett)
|
||||
if (event.getRawDate().length() == 10) continue;
|
||||
|
||||
Date eventDate = null;
|
||||
// Enkel parsing. Merk: Google sender med tidssone (+01:00),
|
||||
// men SimpleDateFormat uten 'X' vil parse dette som lokal tid hvis formatet stemmer.
|
||||
// For optimal tidssone-håndtering burde vi brukt java.time (Android 8+),
|
||||
// men dette fungerer greit så lenge telefonen er i samme sone som kalenderen.
|
||||
if (event.getRawDate().contains("T")) {
|
||||
// Kutter vekk tidssone-offset for enkel parsing til lokal tid
|
||||
String raw = event.getRawDate();
|
||||
if (raw.length() > 19) raw = raw.substring(0, 19);
|
||||
eventDate = isoFormat.parse(raw);
|
||||
|
|
@ -85,14 +75,26 @@ public class NotificationWorker extends Worker {
|
|||
|
||||
if (eventDate == null) continue;
|
||||
|
||||
// Beregn når alarmen skal gå
|
||||
long triggerTime = eventDate.getTime() - (event.getReminderMinutes() * 60 * 1000L);
|
||||
|
||||
// Vi setter alarmen hvis tidspunktet er i fremtiden
|
||||
// Vi sjekker også at det ikke er mer enn 24 timer frem i tid (for å spare ressurser)
|
||||
// --- DETALJERT LOGGING FOR Å FEILSØKE ---
|
||||
if (event.getTitle().toLowerCase().contains("test")) {
|
||||
Log.d(TAG, "SJEKKER TEST-EVENT:");
|
||||
Log.d(TAG, " Start: " + eventDate);
|
||||
Log.d(TAG, " Varsling valgt: " + event.getReminderMinutes() + " min før");
|
||||
Log.d(TAG, " Alarmtid: " + new Date(triggerTime));
|
||||
Log.d(TAG, " Nå: " + new Date(now));
|
||||
|
||||
if (triggerTime > now) {
|
||||
Log.d(TAG, " Status: I FREMTIDEN (Alarm skal settes)");
|
||||
} else {
|
||||
Log.d(TAG, " Status: I FORTIDEN (Hoppes over)");
|
||||
}
|
||||
}
|
||||
// ----------------------------------------
|
||||
|
||||
if (triggerTime > now && triggerTime < (now + 24 * 60 * 60 * 1000L)) {
|
||||
|
||||
// Lag en unik ID for alarmen
|
||||
String uniqueIdString = event.getTitle() + event.getRawDate();
|
||||
int alarmId = uniqueIdString.hashCode();
|
||||
|
||||
|
|
@ -108,17 +110,13 @@ public class NotificationWorker extends Worker {
|
|||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
|
||||
);
|
||||
|
||||
// VIKTIG ENDRING: Vi setter alarmen PÅ NYTT hver gang.
|
||||
// AlarmManager overskriver automatisk hvis ID er lik.
|
||||
// Dette sikrer at alarmen faktisk ligger der, selv etter omstart av tlf.
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
|
||||
} else {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
|
||||
}
|
||||
|
||||
Log.i(TAG, ">>> ALARM SATT (Oppdatert): " + event.getTitle() + " -> Skal ringe: " + new Date(triggerTime));
|
||||
Log.i(TAG, ">>> ALARM SATT: " + event.getTitle());
|
||||
countSet++;
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +126,7 @@ public class NotificationWorker extends Worker {
|
|||
}
|
||||
|
||||
if (countSet == 0) {
|
||||
Log.d(TAG, "Ingen kommende alarmer (innenfor neste 24t) funnet akkurat nå.");
|
||||
Log.d(TAG, "Ingen nye alarmer satt (ingen hendelser innenfor neste 24t).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import okhttp3.Interceptor;
|
|||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.logging.HttpLoggingInterceptor; // NY IMPORT
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
|
|
@ -22,12 +22,16 @@ public class RetrofitClient {
|
|||
public static WordPressApiService getApiService() {
|
||||
if (retrofit == null) {
|
||||
|
||||
// NYTT: Logging Interceptor
|
||||
// ENDRET: Redusert loggnivå fra BODY til BASIC for å unngå spam i Logcat
|
||||
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BODY); // Logger ALT (Body, Headers)
|
||||
if (BuildConfig.DEBUG) {
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
|
||||
} else {
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
|
||||
}
|
||||
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.addInterceptor(logging) // Legg til loggingen her
|
||||
.addInterceptor(logging)
|
||||
.addInterceptor(new Interceptor() {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
|
|
@ -46,7 +50,7 @@ public class RetrofitClient {
|
|||
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(new TypeToken<List<GravityField.Choice>>(){}.getType(), new ChoicesAdapter())
|
||||
.setLenient() // NYTT: Gjør parsing litt mer tilgivende
|
||||
.setLenient()
|
||||
.create();
|
||||
|
||||
retrofit = new Retrofit.Builder()
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@ android {
|
|||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
// NYTT: Dette må til for å kunne bruke BuildConfig.DEBUG i koden
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
|
|
@ -69,7 +74,6 @@ android {
|
|||
}
|
||||
}
|
||||
compileOptions {
|
||||
// ENDRET: Oppgradert til Java 11 for å fikse build warnings
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
|
@ -175,11 +179,15 @@ FILSTI: app\src\main\AndroidManifest.xml
|
|||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<application
|
||||
android:name=".KbsApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
|
|
@ -194,7 +202,8 @@ FILSTI: app\src\main\AndroidManifest.xml
|
|||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.KBSIntranett">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
|
@ -203,7 +212,10 @@ FILSTI: app\src\main\AndroidManifest.xml
|
|||
|
||||
<activity android:name=".WebViewActivity" />
|
||||
|
||||
<receiver android:name=".AlarmReceiver" android:exported="false" />
|
||||
<receiver
|
||||
android:name=".AlarmReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
|
@ -224,20 +236,23 @@ FILSTI: app\src\main\java\com\kbs\kbsintranett\AlarmReceiver.java
|
|||
============================================================
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
public class AlarmReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "KBS_DEBUG";
|
||||
private static final String CHANNEL_ID = "kbs_calendar_channel";
|
||||
private static final String CHANNEL_NAME = "KBS Kalendervarsler";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
|
@ -245,45 +260,51 @@ public class AlarmReceiver extends BroadcastReceiver {
|
|||
String message = intent.getStringExtra("MESSAGE");
|
||||
int notificationId = intent.getIntExtra("ID", 0);
|
||||
|
||||
Log.i(TAG, "AlarmReceiver: WAKE UP! Mottok alarm for: " + title);
|
||||
|
||||
createNotificationChannel(context);
|
||||
showNotification(context, title, message, notificationId);
|
||||
}
|
||||
|
||||
private void showNotification(Context context, String title, String message, int notificationId) {
|
||||
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "KBS Kalender", NotificationManager.IMPORTANCE_HIGH);
|
||||
channel.setDescription("Varsler for kalenderhendelser");
|
||||
manager.createNotificationChannel(channel);
|
||||
// Sjekk rettigheter for Android 13+
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
// Vi kan ikke vise varsel uten rettighet.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Intent openAppIntent = new Intent(context, MainActivity.class);
|
||||
openAppIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
// Intent for hva som skjer når man trykker på varselet (åpne appen)
|
||||
Intent tapIntent = new Intent(context, MainActivity.class);
|
||||
tapIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
openAppIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
|
||||
tapIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setSmallIcon(R.drawable.ic_launcher_foreground) // Pass på at du har et ikon her, ellers bruk R.mipmap.ic_launcher
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setCategory(NotificationCompat.CATEGORY_EVENT)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true);
|
||||
|
||||
try {
|
||||
manager.notify(notificationId, builder.build());
|
||||
Log.d(TAG, "AlarmReceiver: Varsel sendt til systemet.");
|
||||
} catch (SecurityException e) {
|
||||
Log.e(TAG, "AlarmReceiver: Feil - Mangler tillatelse til å sende varsel!", e);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "AlarmReceiver: Ukjent feil ved visning av varsel", e);
|
||||
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
notificationManager.notify(notificationId, builder.build());
|
||||
}
|
||||
|
||||
private void createNotificationChannel(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
int importance = NotificationManager.IMPORTANCE_HIGH;
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance);
|
||||
channel.setDescription("Varsler for kalenderhendelser i KBS Intranett");
|
||||
|
||||
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||
if (notificationManager != null) {
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -742,6 +763,7 @@ import android.content.Context;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.provider.CalendarContract;
|
||||
import android.util.Log;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -755,12 +777,10 @@ public class CalendarManager {
|
|||
|
||||
// --- KONFIGURASJON FOR GOOGLE DIREKTE-KOBLING ---
|
||||
private static final String GOOGLE_CALENDAR_ID = "kbservice.no_o2bmp5f9f540vedveit51optfo@group.calendar.google.com";
|
||||
|
||||
// TODO: Sett inn din API-nøkkel her!
|
||||
private static final String GOOGLE_API_KEY = "AIzaSyCos8VW5mClUcuhs86gbSJo8uitY0fVPus";
|
||||
|
||||
public static String getGoogleCalendarUrl() {
|
||||
// Hent hendelser fra 1 år tilbake i tid
|
||||
long oneYearAgo = System.currentTimeMillis() - (365L * 24 * 60 * 60 * 1000);
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
|
@ -772,10 +792,9 @@ public class CalendarManager {
|
|||
+ "&singleEvents=true"
|
||||
+ "&orderBy=startTime"
|
||||
+ "&maxResults=250"
|
||||
+ "&timeMin=" + timeMin; // URL-encoded er ikke nødvendig her siden Retrofit/OkHttp håndterer det, men timeMin bør være formatert
|
||||
+ "&timeMin=" + timeMin;
|
||||
}
|
||||
|
||||
// Konverterer Google Response til vår interne CalendarEvent
|
||||
public static List<CalendarEvent> convertGoogleResponse(GoogleCalendarModels.Response response) {
|
||||
List<CalendarEvent> events = new ArrayList<>();
|
||||
if (response == null || response.items == null) return events;
|
||||
|
|
@ -791,50 +810,69 @@ public class CalendarManager {
|
|||
|
||||
if (item.start != null) {
|
||||
if (item.start.dateTime != null) start = item.start.dateTime;
|
||||
else start = item.start.date; // Heldags
|
||||
else start = item.start.date;
|
||||
}
|
||||
if (item.end != null) {
|
||||
if (item.end.dateTime != null) end = item.end.dateTime;
|
||||
else end = item.end.date; // Heldags
|
||||
else end = item.end.date;
|
||||
}
|
||||
|
||||
// Varslings-logikk (Henter de sanne innstillingene)
|
||||
// --- SPY LOGGING (Se i Logcat etter KBS_DEBUG) ---
|
||||
if (title.toLowerCase().contains("test")) {
|
||||
Log.d("KBS_DEBUG", "--------------------------------------------------");
|
||||
Log.d("KBS_DEBUG", "ANALYSERER EVENT: " + title);
|
||||
Log.d("KBS_DEBUG", " Starttid: " + start);
|
||||
|
||||
if (item.reminders != null) {
|
||||
Log.d("KBS_DEBUG", " useDefault: " + item.reminders.useDefault);
|
||||
|
||||
if (item.reminders.overrides != null && !item.reminders.overrides.isEmpty()) {
|
||||
Log.d("KBS_DEBUG", " Fant " + item.reminders.overrides.size() + " overstyringer:");
|
||||
for (GoogleCalendarModels.Override override : item.reminders.overrides) {
|
||||
Log.d("KBS_DEBUG", " -> Metode: '" + override.method + "', Minutter: " + override.minutes);
|
||||
}
|
||||
} else {
|
||||
Log.d("KBS_DEBUG", " Ingen 'overrides' (spesifikke varsler) funnet i listen fra Google.");
|
||||
}
|
||||
} else {
|
||||
Log.d("KBS_DEBUG", " Ingen 'reminders'-seksjon funnet i JSON-responsen.");
|
||||
}
|
||||
Log.d("KBS_DEBUG", "--------------------------------------------------");
|
||||
}
|
||||
// -------------------------------------------------
|
||||
|
||||
// Varslings-logikk
|
||||
int reminderMinutes = 15; // Default fallback
|
||||
|
||||
if (item.reminders != null) {
|
||||
if (item.reminders.useDefault) {
|
||||
reminderMinutes = 15; // Standard i Google er ofte 10 eller 15, vi antar 15
|
||||
} else if (item.reminders.overrides != null) {
|
||||
for (GoogleCalendarModels.Override override : item.reminders.overrides) {
|
||||
if ("popup".equalsIgnoreCase(override.method) || "alert".equalsIgnoreCase(override.method)) {
|
||||
reminderMinutes = override.minutes;
|
||||
break; // Bruk den første popup-varslingen vi finner
|
||||
}
|
||||
}
|
||||
reminderMinutes = 15;
|
||||
} else if (item.reminders.overrides != null && !item.reminders.overrides.isEmpty()) {
|
||||
// Vi tar den første vi finner for å se om det fanger opp dine 10/26 minutter
|
||||
reminderMinutes = item.reminders.overrides.get(0).minutes;
|
||||
}
|
||||
}
|
||||
|
||||
CalendarEvent event = new CalendarEvent(title, start, end, desc, loc);
|
||||
event.setReminderMinutes(reminderMinutes);
|
||||
|
||||
// Formatér for UI med en gang
|
||||
formatEventForUI(event);
|
||||
|
||||
events.add(event);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
// --- EKSISTERENDE KODE (UENDRET UNDER) ---
|
||||
// --- RESTERENDE KODE (UENDRET) ---
|
||||
|
||||
// NY HJELPEMETODE: Finner ID-ene til kalendere som tilhører @kbs.no
|
||||
private static List<String> getKbsCalendarIds(Context context) {
|
||||
List<String> ids = new ArrayList<>();
|
||||
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
|
||||
return ids;
|
||||
}
|
||||
String[] projection = new String[] {
|
||||
CalendarContract.Calendars._ID,
|
||||
CalendarContract.Calendars.ACCOUNT_NAME
|
||||
};
|
||||
// Vi ser etter kontoer som slutter på @kbs.no
|
||||
// (SQL: account_name LIKE '%@kbs.no')
|
||||
String selection = CalendarContract.Calendars.ACCOUNT_NAME + " LIKE ?";
|
||||
String[] selectionArgs = new String[] {"%@kbs.no"};
|
||||
|
||||
|
|
@ -848,7 +886,6 @@ public class CalendarManager {
|
|||
if (cursor != null) {
|
||||
while (cursor.moveToNext()) {
|
||||
ids.add(cursor.getString(0));
|
||||
// Legg til kalender-ID
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
@ -864,17 +901,15 @@ public class CalendarManager {
|
|||
return deviceEvents;
|
||||
}
|
||||
|
||||
// 1. Finn først ID-ene til KBS-kalenderne
|
||||
List<String> kbsCalendarIds = getKbsCalendarIds(context);
|
||||
// Hvis ingen kbs-kalendere finnes på telefonen, returner tom liste
|
||||
if (kbsCalendarIds.isEmpty()) {
|
||||
return deviceEvents;
|
||||
}
|
||||
|
||||
// Hent events fra 1 år tilbake og 1 år frem
|
||||
long now = System.currentTimeMillis();
|
||||
long startMillis = now - (365L * 24 * 60 * 60 * 1000);
|
||||
long endMillis = now + (365L * 24 * 60 * 60 * 1000);
|
||||
|
||||
String[] projection = new String[]{
|
||||
CalendarContract.Events.TITLE,
|
||||
CalendarContract.Events.DTSTART,
|
||||
|
|
@ -884,8 +919,6 @@ public class CalendarManager {
|
|||
CalendarContract.Events.ALL_DAY
|
||||
};
|
||||
|
||||
// 2. Bygg opp spørringen for å filtrere på disse ID-ene
|
||||
// Resultatet blir noe sånt som: "((calendar_id = ?) OR (calendar_id = ?)) AND dtstart >= ? AND dtstart <= ?"
|
||||
StringBuilder selection = new StringBuilder("(");
|
||||
List<String> selectionArgsList = new ArrayList<>();
|
||||
|
||||
|
|
@ -904,6 +937,7 @@ public class CalendarManager {
|
|||
selectionArgsList.add(String.valueOf(endMillis));
|
||||
|
||||
String[] selectionArgs = selectionArgsList.toArray(new String[0]);
|
||||
|
||||
try (Cursor cursor = context.getContentResolver().query(
|
||||
CalendarContract.Events.CONTENT_URI,
|
||||
projection,
|
||||
|
|
@ -920,6 +954,7 @@ public class CalendarManager {
|
|||
String desc = cursor.getString(3);
|
||||
String loc = cursor.getString(4);
|
||||
int allDay = cursor.getInt(5);
|
||||
|
||||
String rawStart;
|
||||
String rawEnd;
|
||||
|
||||
|
|
@ -945,9 +980,11 @@ public class CalendarManager {
|
|||
|
||||
public static void formatEventForUI(CalendarEvent event) {
|
||||
if (event.getRawDate() == null) return;
|
||||
|
||||
SimpleDateFormat outputDay = new SimpleDateFormat("dd", Locale.getDefault());
|
||||
SimpleDateFormat outputMonth = new SimpleDateFormat("MMM", new Locale("no", "NO"));
|
||||
SimpleDateFormat outputTime = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
|
||||
outputMonth.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
outputTime.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
|
||||
|
|
@ -957,6 +994,7 @@ public class CalendarManager {
|
|||
boolean isAllDay = false;
|
||||
|
||||
String raw = event.getRawDate();
|
||||
|
||||
if (raw.length() == 10 && !raw.contains("T") && !raw.contains(" ")) {
|
||||
SimpleDateFormat shortFmt = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
date = shortFmt.parse(raw);
|
||||
|
|
@ -1014,6 +1052,7 @@ public class CalendarManager {
|
|||
String d2 = e2.getRawDate() != null ? e2.getRawDate() : "";
|
||||
return d1.compareTo(d2);
|
||||
});
|
||||
|
||||
return all;
|
||||
}
|
||||
}
|
||||
|
|
@ -4325,6 +4364,45 @@ public class InternalLinkMovementMethod extends LinkMovementMethod {
|
|||
}
|
||||
}
|
||||
|
||||
============================================================
|
||||
FILSTI: app\src\main\java\com\kbs\kbsintranett\KbsApplication.java
|
||||
============================================================
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.os.Build;
|
||||
|
||||
public class KbsApplication extends Application {
|
||||
|
||||
public static final String CHANNEL_ID = "kbs_calendar_channel";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
createNotificationChannel();
|
||||
}
|
||||
|
||||
private void createNotificationChannel() {
|
||||
// Vi oppretter kanalen her ved oppstart, så den er klar uansett om
|
||||
// det er MainActivity eller en bakgrunnsjobb som trenger den.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
"KBS Kalendervarsler",
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
);
|
||||
channel.setDescription("Varsler for kalenderhendelser");
|
||||
|
||||
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||
if (manager != null) {
|
||||
manager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
============================================================
|
||||
FILSTI: app\src\main\java\com\kbs\kbsintranett\LoginFragment.java
|
||||
============================================================
|
||||
|
|
@ -4497,10 +4575,14 @@ FILSTI: app\src\main\java\com\kbs\kbsintranett\MainActivity.java
|
|||
============================================================
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -4508,11 +4590,15 @@ import android.provider.Settings;
|
|||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.ExistingPeriodicWorkPolicy;
|
||||
import androidx.work.PeriodicWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignIn;
|
||||
|
|
@ -4521,31 +4607,42 @@ import com.google.android.gms.auth.api.signin.GoogleSignInClient;
|
|||
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
// VIKTIG: Erstatt denne med din Web Client ID
|
||||
// VIKTIG: Sørg for at denne matcher den du har i Google Cloud Console
|
||||
public static final String GOOGLE_WEB_CLIENT_ID = "SECRET.apps.googleusercontent.com";
|
||||
|
||||
private static final String TAG = "MainActivity";
|
||||
private NavController navController;
|
||||
private BottomNavigationView bottomNav;
|
||||
|
||||
// Launcher for å spørre om varslingstillatelse (Android 13+)
|
||||
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
// 1. Setup UI
|
||||
// --- 1. SETUP UI & NAVIGASJON ---
|
||||
// Sjekket activity_main.xml: ID er "bottom_nav_view"
|
||||
bottomNav = findViewById(R.id.bottom_nav_view);
|
||||
|
||||
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.nav_host_fragment);
|
||||
|
||||
if (navHostFragment != null) {
|
||||
navController = navHostFragment.getNavController();
|
||||
NavigationUI.setupWithNavController(bottomNav, navController);
|
||||
if (bottomNav != null) {
|
||||
NavigationUI.setupWithNavController(bottomNav, navController);
|
||||
}
|
||||
|
||||
// Skjul meny på login-skjerm
|
||||
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
|
||||
// Sjekker mot R.id.navigation_login som er ID'en til fragmentet
|
||||
if (bottomNav == null) return;
|
||||
|
||||
if (destination.getId() == R.id.navigation_login) {
|
||||
bottomNav.setVisibility(View.GONE);
|
||||
} else {
|
||||
|
|
@ -4554,50 +4651,32 @@ public class MainActivity extends AppCompatActivity {
|
|||
});
|
||||
}
|
||||
|
||||
// --- NYTT: Sjekk tillatelse for nøyaktige alarmer (Android 12+) ---
|
||||
// --- 2. VARSLINGSOPPSETT (NYTT) ---
|
||||
createNotificationChannel();
|
||||
|
||||
// Initialiser permission launcher for varsler
|
||||
requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
|
||||
if (isGranted) {
|
||||
Log.d(TAG, "Varslingstillatelse gitt!");
|
||||
} else {
|
||||
Log.e(TAG, "Varslingstillatelse avslått. Bruker får ikke kalendervarsler.");
|
||||
}
|
||||
});
|
||||
|
||||
// Sjekk tillatelser (både Varsler og Alarmer)
|
||||
checkNotificationPermission();
|
||||
checkExactAlarmPermission();
|
||||
|
||||
// 2. Start Silent Sign-In ved oppstart
|
||||
// Start bakgrunnsjobben for kalenderen
|
||||
scheduleCalendarWork();
|
||||
|
||||
// --- 3. AUTENTISERING (GAMMELT) ---
|
||||
checkLoginState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sjekker om appen har lov til å sette nøyaktige alarmer (SCHEDULE_EXACT_ALARM).
|
||||
* Hvis ikke, spør brukeren om å gå til innstillinger.
|
||||
* Sjekker om brukeren er logget inn med Google, og gjør en silent refresh mot WP.
|
||||
*/
|
||||
private void checkExactAlarmPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
if (alarmManager != null && !alarmManager.canScheduleExactAlarms()) {
|
||||
// Vi mangler tillatelse. Vis dialog.
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Varslingstillatelse kreves")
|
||||
.setMessage("For at kalenderen skal kunne varsle deg nøyaktig når et møte starter, må du gi appen tilgang til å sette alarmer.")
|
||||
.setPositiveButton("Gå til Innstillinger", (dialog, which) -> {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
|
||||
intent.setData(Uri.parse("package:" + getPackageName()));
|
||||
startActivity(intent);
|
||||
})
|
||||
.setNegativeButton("Senere", null)
|
||||
.show();
|
||||
} else {
|
||||
// Vi har tillatelse (eller er på eldre Android). Kjør logikk!
|
||||
runNotificationWorker();
|
||||
}
|
||||
} else {
|
||||
// Eldre Android-versjoner trenger ikke denne tillatelsen
|
||||
runNotificationWorker();
|
||||
}
|
||||
}
|
||||
|
||||
private void runNotificationWorker() {
|
||||
// --- DEBUG: TVING KJØRING AV KALENDER-SJEKK ---
|
||||
// Denne linjen kjører NotificationWorker umiddelbart ved oppstart for feilsøking.
|
||||
// Fjern eller kommenter ut denne når testingen er ferdig.
|
||||
WorkManager.getInstance(this).enqueue(OneTimeWorkRequest.from(NotificationWorker.class));
|
||||
// ----------------------------------------------
|
||||
}
|
||||
|
||||
private void checkLoginState() {
|
||||
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
|
||||
if (account == null) {
|
||||
|
|
@ -4627,10 +4706,8 @@ public class MainActivity extends AppCompatActivity {
|
|||
@Override
|
||||
public void onSuccess(String role) {
|
||||
Log.d(TAG, "Silent login fullført. Rolle: " + role);
|
||||
// Gå videre til Home hvis vi står på Login
|
||||
if (navController != null && navController.getCurrentDestination() != null &&
|
||||
navController.getCurrentDestination().getId() == R.id.navigation_login) {
|
||||
// Denne aksjonen finnes i mobile_navigation.xml
|
||||
navController.navigate(R.id.action_login_to_home);
|
||||
}
|
||||
}
|
||||
|
|
@ -4652,13 +4729,71 @@ public class MainActivity extends AppCompatActivity {
|
|||
private void navigateToLogin() {
|
||||
if (navController != null) {
|
||||
if (navController.getCurrentDestination() != null &&
|
||||
// Sjekker mot R.id.navigation_login som er ID'en til fragmentet
|
||||
navController.getCurrentDestination().getId() != R.id.navigation_login) {
|
||||
// Denne ID'en finnes i mobile_navigation.xml
|
||||
navController.navigate(R.id.navigation_login);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- NYE HJELPEMETODER FOR VARSLING ---
|
||||
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
CharSequence name = "KBS Kalendervarsler";
|
||||
String description = "Varsler for kalenderhendelser";
|
||||
int importance = NotificationManager.IMPORTANCE_HIGH;
|
||||
NotificationChannel channel = new NotificationChannel("kbs_calendar_channel", name, importance);
|
||||
channel.setDescription(description);
|
||||
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
||||
if (notificationManager != null) {
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNotificationPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sjekker om appen har lov til å sette nøyaktige alarmer (SCHEDULE_EXACT_ALARM).
|
||||
* Hvis ikke, spør brukeren om å gå til innstillinger.
|
||||
*/
|
||||
private void checkExactAlarmPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
if (alarmManager != null && !alarmManager.canScheduleExactAlarms()) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Varslingstillatelse kreves")
|
||||
.setMessage("For at kalenderen skal kunne varsle deg nøyaktig når et møte starter, må du gi appen tilgang til å sette alarmer.")
|
||||
.setPositiveButton("Gå til Innstillinger", (dialog, which) -> {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
|
||||
intent.setData(Uri.parse("package:" + getPackageName()));
|
||||
startActivity(intent);
|
||||
})
|
||||
.setNegativeButton("Senere", null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starter WorkManager som sjekker kalenderen hvert 15. minutt.
|
||||
*/
|
||||
private void scheduleCalendarWork() {
|
||||
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(NotificationWorker.class, 15, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
||||
"KbsCalendarWork",
|
||||
ExistingPeriodicWorkPolicy.UPDATE,
|
||||
workRequest
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
============================================================
|
||||
|
|
@ -5044,7 +5179,6 @@ public class NotificationWorker extends Worker {
|
|||
|
||||
try {
|
||||
String url = CalendarManager.getGoogleCalendarUrl();
|
||||
// Hent events synkront
|
||||
Response<GoogleCalendarModels.Response> response = RetrofitClient.getApiService().getDirectGoogleEvents(url).execute();
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
|
|
@ -5065,32 +5199,23 @@ public class NotificationWorker extends Worker {
|
|||
Context context = getApplicationContext();
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
// Sjekk rettigheter (Android 12+)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
if (!alarmManager.canScheduleExactAlarms()) {
|
||||
Log.e(TAG, "NotificationWorker: MANGLER fortsatt tillatelse! Gå til Innstillinger -> Apper -> KBS -> Alarmer og påminnelser.");
|
||||
Log.e(TAG, "NotificationWorker: MANGLER fortsatt tillatelse!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
// Bruker en parser som er litt mer fleksibel for datoer
|
||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
|
||||
int countSet = 0;
|
||||
|
||||
for (CalendarEvent event : events) {
|
||||
try {
|
||||
// Hopp over heldagshendelser (dato uten klokkeslett)
|
||||
if (event.getRawDate().length() == 10) continue;
|
||||
|
||||
Date eventDate = null;
|
||||
// Enkel parsing. Merk: Google sender med tidssone (+01:00),
|
||||
// men SimpleDateFormat uten 'X' vil parse dette som lokal tid hvis formatet stemmer.
|
||||
// For optimal tidssone-håndtering burde vi brukt java.time (Android 8+),
|
||||
// men dette fungerer greit så lenge telefonen er i samme sone som kalenderen.
|
||||
if (event.getRawDate().contains("T")) {
|
||||
// Kutter vekk tidssone-offset for enkel parsing til lokal tid
|
||||
String raw = event.getRawDate();
|
||||
if (raw.length() > 19) raw = raw.substring(0, 19);
|
||||
eventDate = isoFormat.parse(raw);
|
||||
|
|
@ -5098,14 +5223,26 @@ public class NotificationWorker extends Worker {
|
|||
|
||||
if (eventDate == null) continue;
|
||||
|
||||
// Beregn når alarmen skal gå
|
||||
long triggerTime = eventDate.getTime() - (event.getReminderMinutes() * 60 * 1000L);
|
||||
|
||||
// Vi setter alarmen hvis tidspunktet er i fremtiden
|
||||
// Vi sjekker også at det ikke er mer enn 24 timer frem i tid (for å spare ressurser)
|
||||
// --- DETALJERT LOGGING FOR Å FEILSØKE ---
|
||||
if (event.getTitle().toLowerCase().contains("test")) {
|
||||
Log.d(TAG, "SJEKKER TEST-EVENT:");
|
||||
Log.d(TAG, " Start: " + eventDate);
|
||||
Log.d(TAG, " Varsling valgt: " + event.getReminderMinutes() + " min før");
|
||||
Log.d(TAG, " Alarmtid: " + new Date(triggerTime));
|
||||
Log.d(TAG, " Nå: " + new Date(now));
|
||||
|
||||
if (triggerTime > now) {
|
||||
Log.d(TAG, " Status: I FREMTIDEN (Alarm skal settes)");
|
||||
} else {
|
||||
Log.d(TAG, " Status: I FORTIDEN (Hoppes over)");
|
||||
}
|
||||
}
|
||||
// ----------------------------------------
|
||||
|
||||
if (triggerTime > now && triggerTime < (now + 24 * 60 * 60 * 1000L)) {
|
||||
|
||||
// Lag en unik ID for alarmen
|
||||
String uniqueIdString = event.getTitle() + event.getRawDate();
|
||||
int alarmId = uniqueIdString.hashCode();
|
||||
|
||||
|
|
@ -5121,17 +5258,13 @@ public class NotificationWorker extends Worker {
|
|||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
|
||||
);
|
||||
|
||||
// VIKTIG ENDRING: Vi setter alarmen PÅ NYTT hver gang.
|
||||
// AlarmManager overskriver automatisk hvis ID er lik.
|
||||
// Dette sikrer at alarmen faktisk ligger der, selv etter omstart av tlf.
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
|
||||
} else {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
|
||||
}
|
||||
|
||||
Log.i(TAG, ">>> ALARM SATT (Oppdatert): " + event.getTitle() + " -> Skal ringe: " + new Date(triggerTime));
|
||||
Log.i(TAG, ">>> ALARM SATT: " + event.getTitle());
|
||||
countSet++;
|
||||
}
|
||||
|
||||
|
|
@ -5141,7 +5274,7 @@ public class NotificationWorker extends Worker {
|
|||
}
|
||||
|
||||
if (countSet == 0) {
|
||||
Log.d(TAG, "Ingen kommende alarmer (innenfor neste 24t) funnet akkurat nå.");
|
||||
Log.d(TAG, "Ingen nye alarmer satt (ingen hendelser innenfor neste 24t).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5260,7 +5393,7 @@ import okhttp3.Interceptor;
|
|||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.logging.HttpLoggingInterceptor; // NY IMPORT
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
|
|
@ -5271,12 +5404,16 @@ public class RetrofitClient {
|
|||
public static WordPressApiService getApiService() {
|
||||
if (retrofit == null) {
|
||||
|
||||
// NYTT: Logging Interceptor
|
||||
// ENDRET: Redusert loggnivå fra BODY til BASIC for å unngå spam i Logcat
|
||||
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BODY); // Logger ALT (Body, Headers)
|
||||
if (BuildConfig.DEBUG) {
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
|
||||
} else {
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
|
||||
}
|
||||
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.addInterceptor(logging) // Legg til loggingen her
|
||||
.addInterceptor(logging)
|
||||
.addInterceptor(new Interceptor() {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
|
|
@ -5295,7 +5432,7 @@ public class RetrofitClient {
|
|||
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(new TypeToken<List<GravityField.Choice>>(){}.getType(), new ChoicesAdapter())
|
||||
.setLenient() // NYTT: Gjør parsing litt mer tilgivende
|
||||
.setLenient()
|
||||
.create();
|
||||
|
||||
retrofit = new Retrofit.Builder()
|
||||
|
|
|
|||
Loading…
Reference in a new issue