Fixes: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles. Change-Id: I63b25512d3bf6e0d3b0cc95d91295f4065175848
201 lines
8.3 KiB
Java
201 lines
8.3 KiB
Java
/*
|
|
* Copyright (C) 2017-2022 The LineageOS Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package org.lineageos.updater;
|
|
|
|
import android.app.AlarmManager;
|
|
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.SharedPreferences;
|
|
import android.os.SystemClock;
|
|
import android.preference.PreferenceManager;
|
|
import android.util.Log;
|
|
|
|
import androidx.core.app.NotificationCompat;
|
|
|
|
import org.json.JSONException;
|
|
import org.lineageos.updater.download.DownloadClient;
|
|
import org.lineageos.updater.misc.Constants;
|
|
import org.lineageos.updater.misc.Utils;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.Date;
|
|
import java.util.UUID;
|
|
|
|
public class UpdatesCheckReceiver extends BroadcastReceiver {
|
|
|
|
private static final String TAG = "UpdatesCheckReceiver";
|
|
|
|
private static final String DAILY_CHECK_ACTION = "daily_check_action";
|
|
private static final String ONESHOT_CHECK_ACTION = "oneshot_check_action";
|
|
|
|
private static final String NEW_UPDATES_NOTIFICATION_CHANNEL =
|
|
"new_updates_notification_channel";
|
|
|
|
@Override
|
|
public void onReceive(final Context context, Intent intent) {
|
|
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
|
|
Utils.cleanupDownloadsDir(context);
|
|
}
|
|
|
|
final SharedPreferences preferences =
|
|
PreferenceManager.getDefaultSharedPreferences(context);
|
|
|
|
if (!Utils.isUpdateCheckEnabled(context)) {
|
|
return;
|
|
}
|
|
|
|
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
|
|
// Set a repeating alarm on boot to check for new updates once per day
|
|
scheduleRepeatingUpdatesCheck(context);
|
|
}
|
|
|
|
if (!Utils.isNetworkAvailable(context)) {
|
|
Log.d(TAG, "Network not available, scheduling new check");
|
|
scheduleUpdatesCheck(context);
|
|
return;
|
|
}
|
|
|
|
final File json = Utils.getCachedUpdateList(context);
|
|
final File jsonNew = new File(json.getAbsolutePath() + UUID.randomUUID());
|
|
String url = Utils.getServerURL(context);
|
|
DownloadClient.DownloadCallback callback = new DownloadClient.DownloadCallback() {
|
|
@Override
|
|
public void onFailure(boolean cancelled) {
|
|
Log.e(TAG, "Could not download updates list, scheduling new check");
|
|
scheduleUpdatesCheck(context);
|
|
}
|
|
|
|
@Override
|
|
public void onResponse(DownloadClient.Headers headers) {
|
|
}
|
|
|
|
@Override
|
|
public void onSuccess() {
|
|
try {
|
|
if (json.exists() && Utils.checkForNewUpdates(json, jsonNew)) {
|
|
showNotification(context);
|
|
updateRepeatingUpdatesCheck(context);
|
|
}
|
|
//noinspection ResultOfMethodCallIgnored
|
|
jsonNew.renameTo(json);
|
|
long currentMillis = System.currentTimeMillis();
|
|
preferences.edit()
|
|
.putLong(Constants.PREF_LAST_UPDATE_CHECK, currentMillis)
|
|
.apply();
|
|
// In case we set a one-shot check because of a previous failure
|
|
cancelUpdatesCheck(context);
|
|
} catch (IOException | JSONException e) {
|
|
Log.e(TAG, "Could not parse list, scheduling new check", e);
|
|
scheduleUpdatesCheck(context);
|
|
}
|
|
}
|
|
};
|
|
|
|
try {
|
|
DownloadClient downloadClient = new DownloadClient.Builder()
|
|
.setUrl(url)
|
|
.setDestination(jsonNew)
|
|
.setDownloadCallback(callback)
|
|
.build();
|
|
downloadClient.start();
|
|
} catch (IOException e) {
|
|
Log.e(TAG, "Could not fetch list, scheduling new check", e);
|
|
scheduleUpdatesCheck(context);
|
|
}
|
|
}
|
|
|
|
private static void showNotification(Context context) {
|
|
NotificationManager notificationManager = context.getSystemService(
|
|
NotificationManager.class);
|
|
NotificationChannel notificationChannel = new NotificationChannel(
|
|
NEW_UPDATES_NOTIFICATION_CHANNEL,
|
|
context.getString(R.string.new_updates_channel_title),
|
|
NotificationManager.IMPORTANCE_LOW);
|
|
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context,
|
|
NEW_UPDATES_NOTIFICATION_CHANNEL);
|
|
notificationBuilder.setSmallIcon(R.drawable.ic_system_update);
|
|
Intent notificationIntent = new Intent(context, UpdatesActivity.class);
|
|
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent,
|
|
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
|
notificationBuilder.setContentIntent(intent);
|
|
notificationBuilder.setContentTitle(context.getString(R.string.new_updates_found_title));
|
|
notificationBuilder.setAutoCancel(true);
|
|
notificationManager.createNotificationChannel(notificationChannel);
|
|
notificationManager.notify(0, notificationBuilder.build());
|
|
}
|
|
|
|
private static PendingIntent getRepeatingUpdatesCheckIntent(Context context) {
|
|
Intent intent = new Intent(context, UpdatesCheckReceiver.class);
|
|
intent.setAction(DAILY_CHECK_ACTION);
|
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
|
|
}
|
|
|
|
public static void updateRepeatingUpdatesCheck(Context context) {
|
|
cancelRepeatingUpdatesCheck(context);
|
|
scheduleRepeatingUpdatesCheck(context);
|
|
}
|
|
|
|
public static void scheduleRepeatingUpdatesCheck(Context context) {
|
|
if (!Utils.isUpdateCheckEnabled(context)) {
|
|
return;
|
|
}
|
|
|
|
PendingIntent updateCheckIntent = getRepeatingUpdatesCheckIntent(context);
|
|
AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
|
|
alarmMgr.setRepeating(AlarmManager.RTC, System.currentTimeMillis() +
|
|
Utils.getUpdateCheckInterval(context), Utils.getUpdateCheckInterval(context),
|
|
updateCheckIntent);
|
|
|
|
Date nextCheckDate = new Date(System.currentTimeMillis() +
|
|
Utils.getUpdateCheckInterval(context));
|
|
Log.d(TAG, "Setting automatic updates check: " + nextCheckDate);
|
|
}
|
|
|
|
public static void cancelRepeatingUpdatesCheck(Context context) {
|
|
AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
|
|
alarmMgr.cancel(getRepeatingUpdatesCheckIntent(context));
|
|
}
|
|
|
|
private static PendingIntent getUpdatesCheckIntent(Context context) {
|
|
Intent intent = new Intent(context, UpdatesCheckReceiver.class);
|
|
intent.setAction(ONESHOT_CHECK_ACTION);
|
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
|
|
}
|
|
|
|
public static void scheduleUpdatesCheck(Context context) {
|
|
long millisToNextCheck = AlarmManager.INTERVAL_HOUR * 2;
|
|
PendingIntent updateCheckIntent = getUpdatesCheckIntent(context);
|
|
AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
|
|
alarmMgr.set(AlarmManager.ELAPSED_REALTIME,
|
|
SystemClock.elapsedRealtime() + millisToNextCheck,
|
|
updateCheckIntent);
|
|
|
|
Date nextCheckDate = new Date(System.currentTimeMillis() + millisToNextCheck);
|
|
Log.d(TAG, "Setting one-shot updates check: " + nextCheckDate);
|
|
}
|
|
|
|
public static void cancelUpdatesCheck(Context context) {
|
|
AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
|
|
alarmMgr.cancel(getUpdatesCheckIntent(context));
|
|
Log.d(TAG, "Cancelling pending one-shot check");
|
|
}
|
|
}
|