Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85daeac0 authored by Mohammed Althaf T's avatar Mohammed Althaf T 😊 Committed by Nishith Khanna
Browse files

Updater: Add network ConnectionStateMonitor

Change-Id: I54847a54e1cb0bff262deb3e57cae30fcd85b26f

Updater: Move ConnectionStateMonitor to kotlin

Change-Id: I7e0a1f68b71afe620706813daf76258b0c1682ae

Updater: Improve ConnectionStateMonitor behaviour

- Keep updater app alive till device back online for network callback.
- Remove network callback once the internet is back.
- Wait 10 seconds before doing anything when the device is online.

Change-Id: I55e631cbf6cec9c19ec13e513a54ceaf10f8b2b9

Updater: Change one-shot check to 15 minutes

- It was two hours previously

Change-Id: I4fb4ae38805cedecbbd3bc86c930dfb4c3c11cc6

Updater: UpdatesCheckReceiver: Make exact alarm work every time

Change-Id: Id950e6c4f44a445f78be60416e159045d120152e

Updater: Simplify activity status for cnstate monitor

Change-Id: I1a46444c35ce40c967a16cc8a5ae2d099e14d62e
parent 029b3eb1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ android_app {
    // Include SettingsLib and its dependencies
    defaults: ["SettingsLibDefaults"],

    srcs: ["src/main/java/**/*.java"],
    srcs: ["src/main/java/**/*.java", "src/main/java/**/*.kt"],
    resource_dirs: ["src/main/res", "src/main/res_aosp"],
    manifest: "src/main/AndroidManifest.xml",

+27 −21
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import androidx.core.app.NotificationCompat;
import androidx.preference.PreferenceManager;

import org.json.JSONException;
import org.lineageos.updater.controller.UpdaterService;
import org.lineageos.updater.download.DownloadClient;
import org.lineageos.updater.misc.Constants;
import org.lineageos.updater.misc.Utils;
@@ -51,26 +52,35 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, Intent intent) {
        final SharedPreferences preferences =
                PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();

        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            Utils.cleanupDownloadsDir(context);
        }

        final SharedPreferences preferences =
                PreferenceManager.getDefaultSharedPreferences(context);
            // Reset resume or update check failed on reboot
            editor.putBoolean(Constants.AUTO_UPDATE_CHECK_FAILED, false).apply();
            editor.putString(Constants.RESUME_DOWNLOAD_ID, "").apply();
        }

        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);
        }
        // Exact alarms does not support repeating, so update to make it
        // work like repeating alarms. To check for update at the exact time.
        updateRepeatingUpdatesCheck(context);

        if (!Utils.isNetworkAvailable(context)) {
            Log.d(TAG, "Network not available, scheduling new check");
            scheduleUpdatesCheck(context);
            if (!UpdaterService.isNetworkCallBackActive()) {
                editor.putBoolean(Constants.AUTO_UPDATE_CHECK_FAILED, true).apply();
                UpdaterService.setupNetworkCallback(true);
            }
            return;
        } else if (UpdaterService.isNetworkCallBackActive()) {
            editor.putBoolean(Constants.AUTO_UPDATE_CHECK_FAILED, false).apply();
            UpdaterService.setupNetworkCallback(false);
        }

        final File json = Utils.getCachedUpdateList(context);
@@ -97,9 +107,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
                    //noinspection ResultOfMethodCallIgnored
                    jsonNew.renameTo(json);
                    long currentMillis = System.currentTimeMillis();
                    preferences.edit()
                            .putLong(Constants.PREF_LAST_UPDATE_CHECK, currentMillis)
                            .apply();
                    editor.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) {
@@ -160,12 +168,10 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {

        PendingIntent updateCheckIntent = getRepeatingUpdatesCheckIntent(context);
        AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
        alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC,
                System.currentTimeMillis() + Utils.getUpdateCheckInterval(context),
                updateCheckIntent);
        long nextCheck = System.currentTimeMillis() + Utils.getUpdateCheckInterval(context);
        alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextCheck, updateCheckIntent);

        Date nextCheckDate = new Date(System.currentTimeMillis() +
                Utils.getUpdateCheckInterval(context));
        Date nextCheckDate = new Date(nextCheck);
        Log.d(TAG, "Setting automatic updates check: " + nextCheckDate);
    }

@@ -181,14 +187,14 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
    }

    public static void scheduleUpdatesCheck(Context context) {
        long millisToNextCheck = AlarmManager.INTERVAL_HOUR * 2;
        long millisToNextCheck = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
        PendingIntent updateCheckIntent = getUpdatesCheckIntent(context);
        AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
        long nextCheck = SystemClock.elapsedRealtime() + millisToNextCheck;
        alarmMgr.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME,
                SystemClock.elapsedRealtime() + millisToNextCheck,
                updateCheckIntent);
                nextCheck, updateCheckIntent);

        Date nextCheckDate = new Date(System.currentTimeMillis() + millisToNextCheck);
        Date nextCheckDate = new Date(nextCheck);
        Log.d(TAG, "Setting one-shot updates check: " + nextCheckDate);
    }

+51 −2
Original line number Diff line number Diff line
@@ -29,6 +29,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ServiceInfo;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -42,6 +45,7 @@ import androidx.preference.PreferenceManager;
import org.lineageos.updater.R;
import org.lineageos.updater.UpdaterReceiver;
import org.lineageos.updater.UpdatesActivity;
import org.lineageos.updater.misc.ConnectionStateMonitor;
import org.lineageos.updater.misc.Constants;
import org.lineageos.updater.misc.StringGenerator;
import org.lineageos.updater.misc.Utils;
@@ -75,6 +79,7 @@ public class UpdaterService extends Service {
    private static final int NOTIFICATION_ID = 10;

    private final IBinder mBinder = new LocalBinder();
    private static boolean isNetworkCallBackActive = false;
    private boolean mHasClients;

    private BroadcastReceiver mBroadcastReceiver;
@@ -84,11 +89,21 @@ public class UpdaterService extends Service {

    private UpdaterController mUpdaterController;

    private static final NetworkRequest networkRequest = new NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .build();
    private static ConnectivityManager.NetworkCallback mConnectionStateMonitor;
    private static ConnectivityManager mConnectivityManager;

    @Override
    public void onCreate() {
        super.onCreate();

        mUpdaterController = UpdaterController.getInstance(this);
        mConnectionStateMonitor = new ConnectionStateMonitor().getInstance(this);
        mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

        mNotificationManager = getSystemService(NotificationManager.class);
        NotificationChannel notificationChannel = new NotificationChannel(
@@ -252,13 +267,15 @@ public class UpdaterService extends Service {

    private void tryStopSelf() {
        if (!mHasClients && !mUpdaterController.hasActiveDownloads() &&
                !mUpdaterController.isInstallingUpdate()) {
                !mUpdaterController.isInstallingUpdate() && !isNetworkCallBackActive()) {
            Log.d(TAG, "Service no longer needed, stopping");
            stopSelf();
        }
    }

    private void handleUpdateStatusChange(UpdateInfo update) {
        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = pref.edit();
        switch (update.getStatus()) {
            case DELETED: {
                notifySystemUpdaterService(STATUS_WAITING_DOWNLOAD, update);
@@ -294,6 +311,10 @@ public class UpdaterService extends Service {
                mNotificationBuilder.addAction(android.R.drawable.ic_media_pause,
                        getString(R.string.pause_button),
                        getPausePendingIntent(update.getDownloadId()));
                if (isNetworkCallBackActive) {
                    editor.putString(Constants.RESUME_DOWNLOAD_ID, "").apply();
                    setupNetworkCallback(false);
                }
                mNotificationBuilder.setTicker(text);
                mNotificationBuilder.setOngoing(true);
                mNotificationBuilder.setAutoCancel(false);
@@ -313,6 +334,10 @@ public class UpdaterService extends Service {
                mNotificationBuilder.addAction(android.R.drawable.ic_media_play,
                        getString(R.string.resume_button),
                        getResumePendingIntent(update.getDownloadId()));
                if (isNetworkCallBackActive) {
                    editor.putString(Constants.RESUME_DOWNLOAD_ID, "").apply();
                    setupNetworkCallback(false);
                }
                mNotificationBuilder.setTicker(text);
                mNotificationBuilder.setOngoing(false);
                mNotificationBuilder.setAutoCancel(false);
@@ -338,6 +363,10 @@ public class UpdaterService extends Service {
                mNotificationBuilder.setOngoing(false);
                mNotificationBuilder.setAutoCancel(false);
                mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
                if (!Utils.isNetworkAvailable(this)) {
                    editor.putString(Constants.RESUME_DOWNLOAD_ID, update.getDownloadId()).apply();
                    setupNetworkCallback(true);
                }
                tryStopSelf();
                break;
            }
@@ -425,7 +454,6 @@ public class UpdaterService extends Service {
                mNotificationBuilder.setAutoCancel(true);
                mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());

                SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
                boolean deleteUpdate = pref.getBoolean(Constants.PREF_AUTO_DELETE_UPDATES, true);
                boolean isLocal = Update.LOCAL_ID.equals(update.getDownloadId());
                // Always delete local updates
@@ -480,6 +508,8 @@ public class UpdaterService extends Service {
        }
    }

    public static boolean isNetworkCallBackActive() { return isNetworkCallBackActive; }

    private void handleDownloadProgressChange(UpdateInfo update) {
        int progress = update.getProgress();
        mNotificationBuilder.setProgress(100, progress, false);
@@ -520,6 +550,25 @@ public class UpdaterService extends Service {
        mNotificationBuilder.setContentTitle(buildInfo);
    }

    public static void setupNetworkCallback(boolean shouldEnable) {
        if (mConnectivityManager == null || mConnectionStateMonitor == null) {
            Log.e(TAG, "Unable to set network callback");
            return;
        }
        if (shouldEnable) {
            mConnectivityManager.registerNetworkCallback(networkRequest, mConnectionStateMonitor);
        } else {
            try {
                mConnectivityManager.unregisterNetworkCallback(mConnectionStateMonitor);
            } catch (IllegalArgumentException | NullPointerException e) {
                Log.e(TAG, "Network callback was not registered");
            }
        }

        isNetworkCallBackActive = shouldEnable;
        Log.d(TAG, "Network callback enabled: " + shouldEnable);
    }

    private PendingIntent getResumePendingIntent(String downloadId) {
        final Intent intent = new Intent(this, UpdaterService.class);
        intent.setAction(ACTION_DOWNLOAD_CONTROL);
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 MURENA SAS
 *
 * 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.misc

import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.ConnectivityManager
import android.net.Network
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.preference.PreferenceManager
import org.lineageos.updater.UpdatesCheckReceiver
import org.lineageos.updater.controller.UpdaterController

class ConnectionStateMonitor {
    companion object {
        private var instance: ConnectivityManager.NetworkCallback? = null
    }

    fun getInstance(context: Context): ConnectivityManager.NetworkCallback {
        if (instance == null) {
            instance = networkCallback(context)
        }

        return instance!!
    }

    /**
     * API callbacks to determine which status we currently in
     * we need the below callbacks:
     * - onAvailable: device connected to a network of course
     * - onLost: when the connection completely lost
     */
    private fun networkCallback(context: Context) = object: ConnectivityManager.NetworkCallback() {
        private val tag = "ConnectionStateMonitor"
        private val pref: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
        private val updaterController: UpdaterController = UpdaterController.getInstance(context)

        private fun checkForUpdatesOrResume() {
            val downloadId: String = pref.getString(Constants.RESUME_DOWNLOAD_ID, "")!!
            if (downloadId.isNotEmpty()) {
                Handler(Looper.getMainLooper()).postDelayed({
                    updaterController.resumeDownload(
                        downloadId
                    )
                }, 2000L) // 2 seconds
            }
            if (pref.getBoolean(Constants.AUTO_UPDATE_CHECK_FAILED, false)) {
                Handler(Looper.getMainLooper()).postDelayed({
                    val broadcastIntent = Intent()
                    broadcastIntent.setClassName(context, UpdatesCheckReceiver::class.java.name)
                    context.sendBroadcast(broadcastIntent)
                }, 10000L) // 10 seconds
            }

        }

        override fun onAvailable(network: Network) {
            Log.d(tag, "Network available")
            checkForUpdatesOrResume()
        }

        override fun onLost(network: Network) {
            Log.d(tag, "Network not available")
            checkForUpdatesOrResume()
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@ public final class Constants {
    public static final String AB_PAYLOAD_BIN_PATH = "payload.bin";
    public static final String AB_PAYLOAD_PROPERTIES_PATH = "payload_properties.txt";

    public static final String RESUME_DOWNLOAD_ID = "resume_download_id";
    public static final String AUTO_UPDATE_CHECK_FAILED = "auto_update_check_failed";

    public static final int AUTO_UPDATES_CHECK_INTERVAL_NEVER = 0;
    public static final int AUTO_UPDATES_CHECK_INTERVAL_DAILY = 1;
    public static final int AUTO_UPDATES_CHECK_INTERVAL_WEEKLY = 2;
@@ -38,6 +41,7 @@ public final class Constants {
    public static final String PREF_METERED_NETWORK_WARNING = "pref_metered_network_warning";
    public static final String PREF_MOBILE_DATA_WARNING = "pref_mobile_data_warning";
    public static final String PREF_NEEDS_REBOOT_ID = "needs_reboot_id";
    public static final String PREF_NETWORK_CALLBACK_ACTIVE = "pref_network_callback_active";

    public static final String UNCRYPT_FILE_EXT = ".uncrypt";