Updater: The great cleanup

* Make final where possible
* Remove unused casts, imports, methods, enums and constructors
* Add null checks

Change-Id: Idd1a16426dd1928e2ed9922f5a35ba32ce4f808b
This commit is contained in:
Michael W
2022-01-31 17:28:01 +01:00
parent bdb6a3ff66
commit 46c06ad958
23 changed files with 340 additions and 401 deletions

View File

@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal" android:orientation="horizontal"
android:id="@+id/main_container" android:id="@+id/main_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
android:padding="16dp" android:padding="16dp"
android:weightSum="2"> android:weightSum="2"
android:baselineAligned="false">
<RelativeLayout <RelativeLayout
android:layout_width="0dp" android:layout_width="0dp"
@@ -29,57 +30,57 @@
android:fontFamily="sans-serif-light" android:fontFamily="sans-serif-light"
android:paddingBottom="16dp" android:paddingBottom="16dp"
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="56sp" /> android:textSize="56sp"
tools:text="LineageOS\n18.1" />
<TextView <TextView
android:id="@+id/header_build_version" android:id="@+id/header_build_version"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/header_title"
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp" /> android:textSize="14sp"
tools:text="Android 11"/>
<TextView <TextView
android:id="@+id/header_build_date" android:id="@+id/header_build_date"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/header_build_version"
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp" /> android:textSize="14sp"
tools:text="2022-01-01"/>
<TextView <TextView
android:id="@+id/header_last_check" android:id="@+id/header_last_check"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/header_build_date"
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp" /> android:textSize="14sp"
tools:text="Last checked: 2022-01-01"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/header_last_check"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:weightSum="2" android:weightSum="2"
android:orientation="horizontal"> android:orientation="horizontal">
<Button <Button
android:id="@+id/refresh" android:id="@+id/refresh"
android:drawableLeft="@drawable/ic_menu_refresh" android:drawableStart="@drawable/ic_menu_refresh"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="refresh" android:text="@string/menu_refresh"
style="@style/Widget.AppCompat.Button.Borderless.Colored"/> style="@style/Widget.AppCompat.Button.Borderless.Colored"/>
<Button <Button
android:id="@+id/preferences" android:id="@+id/preferences"
android:drawableLeft="@drawable/ic_menu_preferences" android:drawableStart="@drawable/ic_menu_preferences"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="preferences" android:text="@string/menu_preferences"
style="@style/Widget.AppCompat.Button.Borderless.Colored"/> style="@style/Widget.AppCompat.Button.Borderless.Colored"/>
</LinearLayout> </LinearLayout>

View File

@@ -16,7 +16,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="horizontal" android:orientation="horizontal"
android:weightSum="1"> android:weightSum="1"
android:baselineAligned="false">
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
@@ -90,7 +91,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="end" android:layout_gravity="end"
android:padding="8dp" /> android:padding="8dp"
android:contentDescription="@null" />
<Button <Button
android:id="@id/update_action" android:id="@id/update_action"
style="@style/Widget.AppCompat.Button.Borderless.Colored" style="@style/Widget.AppCompat.Button.Borderless.Colored"

View File

@@ -29,7 +29,7 @@
android:entries="@array/menu_auto_updates_check_interval_entries" /> android:entries="@array/menu_auto_updates_check_interval_entries" />
</LinearLayout> </LinearLayout>
<Switch <androidx.appcompat.widget.SwitchCompat
android:id="@+id/preferences_auto_delete_updates" android:id="@+id/preferences_auto_delete_updates"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -37,7 +37,7 @@
android:text="@string/menu_auto_delete_updates" android:text="@string/menu_auto_delete_updates"
android:textSize="16sp" /> android:textSize="16sp" />
<Switch <androidx.appcompat.widget.SwitchCompat
android:id="@+id/preferences_mobile_data_warning" android:id="@+id/preferences_mobile_data_warning"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -45,7 +45,7 @@
android:text="@string/menu_mobile_data_warning" android:text="@string/menu_mobile_data_warning"
android:textSize="16sp" /> android:textSize="16sp" />
<Switch <androidx.appcompat.widget.SwitchCompat
android:id="@+id/preferences_ab_perf_mode" android:id="@+id/preferences_ab_perf_mode"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -53,7 +53,7 @@
android:text="@string/menu_ab_perf_mode" android:text="@string/menu_ab_perf_mode"
android:textSize="16sp" /> android:textSize="16sp" />
<Switch <androidx.appcompat.widget.SwitchCompat
android:id="@+id/preferences_update_recovery" android:id="@+id/preferences_update_recovery"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -15,7 +15,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="horizontal" android:orientation="horizontal"
android:weightSum="1"> android:weightSum="1"
android:baselineAligned="false">
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
@@ -89,7 +90,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="end" android:layout_gravity="end"
android:padding="8dp" /> android:padding="8dp"
android:contentDescription="@null" />
<Button <Button
android:id="@id/update_action" android:id="@id/update_action"
style="@style/Widget.AppCompat.Button.Borderless.Colored" style="@style/Widget.AppCompat.Button.Borderless.Colored"

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/menu_export_update" android:id="@+id/menu_export_update"
android:title="@string/menu_export_update" /> android:title="@string/menu_export_update" />

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -94,11 +94,11 @@ public class ExportUpdateService extends Service {
} }
private class ExportRunnable implements Runnable { private class ExportRunnable implements Runnable {
private File mSource; private final File mSource;
private File mDestination; private final File mDestination;
private FileUtils.ProgressCallBack mProgressCallBack; private final FileUtils.ProgressCallBack mProgressCallBack;
private Runnable mRunnableComplete; private final Runnable mRunnableComplete;
private Runnable mRunnableFailed; private final Runnable mRunnableFailed;
private ExportRunnable(File source, File destination, private ExportRunnable(File source, File destination,
FileUtils.ProgressCallBack progressCallBack, FileUtils.ProgressCallBack progressCallBack,
@@ -131,13 +131,13 @@ public class ExportUpdateService extends Service {
} }
private void cleanUp() { private void cleanUp() {
//noinspection ResultOfMethodCallIgnored
mDestination.delete(); mDestination.delete();
} }
} }
private void startExporting(File source, File destination) { private void startExporting(File source, File destination) {
NotificationManager notificationManager = NotificationManager notificationManager = getSystemService(NotificationManager.class);
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel( NotificationChannel notificationChannel = new NotificationChannel(
EXPORT_NOTIFICATION_CHANNEL, EXPORT_NOTIFICATION_CHANNEL,
getString(R.string.export_channel_title), getString(R.string.export_channel_title),

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -79,8 +79,7 @@ public class UpdaterReceiver extends BroadcastReceiver {
.setStyle(new NotificationCompat.BigTextStyle().bigText(buildInfo)) .setStyle(new NotificationCompat.BigTextStyle().bigText(buildInfo))
.setContentText(buildInfo); .setContentText(buildInfo);
NotificationManager nm = (NotificationManager) context.getSystemService( NotificationManager nm = context.getSystemService(NotificationManager.class);
Context.NOTIFICATION_SERVICE);
nm.createNotificationChannel(notificationChannel); nm.createNotificationChannel(notificationChannel);
nm.notify(0, builder.build()); nm.notify(0, builder.build());
} }
@@ -88,7 +87,7 @@ public class UpdaterReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (ACTION_INSTALL_REBOOT.equals(intent.getAction())) { if (ACTION_INSTALL_REBOOT.equals(intent.getAction())) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager pm = context.getSystemService(PowerManager.class);
pm.reboot(null); pm.reboot(null);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { } else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017-2020 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/ */
package org.lineageos.updater; package org.lineageos.updater;
import android.annotation.SuppressLint;
import android.app.UiModeManager; import android.app.UiModeManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
@@ -39,14 +40,13 @@ import android.view.View;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.LinearInterpolator; import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation; import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@@ -92,10 +92,10 @@ public class UpdatesActivity extends UpdatesListActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_updates); setContentView(R.layout.activity_updates);
UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE); UiModeManager uiModeManager = getSystemService(UiModeManager.class);
mIsTV = uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; mIsTV = uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); RecyclerView recyclerView = findViewById(R.id.recycler_view);
mAdapter = new UpdatesListAdapter(this); mAdapter = new UpdatesListAdapter(this);
recyclerView.setAdapter(mAdapter); recyclerView.setAdapter(mAdapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
@@ -111,7 +111,7 @@ public class UpdatesActivity extends UpdatesListActivity {
if (UpdaterController.ACTION_UPDATE_STATUS.equals(intent.getAction())) { if (UpdaterController.ACTION_UPDATE_STATUS.equals(intent.getAction())) {
String downloadId = intent.getStringExtra(UpdaterController.EXTRA_DOWNLOAD_ID); String downloadId = intent.getStringExtra(UpdaterController.EXTRA_DOWNLOAD_ID);
handleDownloadStatusChange(downloadId); handleDownloadStatusChange(downloadId);
mAdapter.notifyDataSetChanged(); mAdapter.notifyItemChanged(downloadId);
} else if (UpdaterController.ACTION_DOWNLOAD_PROGRESS.equals(intent.getAction()) || } else if (UpdaterController.ACTION_DOWNLOAD_PROGRESS.equals(intent.getAction()) ||
UpdaterController.ACTION_INSTALL_PROGRESS.equals(intent.getAction())) { UpdaterController.ACTION_INSTALL_PROGRESS.equals(intent.getAction())) {
String downloadId = intent.getStringExtra(UpdaterController.EXTRA_DOWNLOAD_ID); String downloadId = intent.getStringExtra(UpdaterController.EXTRA_DOWNLOAD_ID);
@@ -124,31 +124,33 @@ public class UpdatesActivity extends UpdatesListActivity {
}; };
if (!mIsTV) { if (!mIsTV) {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false); ActionBar actionBar = getSupportActionBar();
getSupportActionBar().setDisplayHomeAsUpEnabled(true); if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true);
}
} }
TextView headerTitle = (TextView) findViewById(R.id.header_title); TextView headerTitle = findViewById(R.id.header_title);
headerTitle.setText(getString(R.string.header_title_text, headerTitle.setText(getString(R.string.header_title_text,
BuildInfoUtils.getBuildVersion())); BuildInfoUtils.getBuildVersion()));
updateLastCheckedString(); updateLastCheckedString();
TextView headerBuildVersion = (TextView) findViewById(R.id.header_build_version); TextView headerBuildVersion = findViewById(R.id.header_build_version);
headerBuildVersion.setText( headerBuildVersion.setText(
getString(R.string.header_android_version, Build.VERSION.RELEASE)); getString(R.string.header_android_version, Build.VERSION.RELEASE));
TextView headerBuildDate = (TextView) findViewById(R.id.header_build_date); TextView headerBuildDate = findViewById(R.id.header_build_date);
headerBuildDate.setText(StringGenerator.getDateLocalizedUTC(this, headerBuildDate.setText(StringGenerator.getDateLocalizedUTC(this,
DateFormat.LONG, BuildInfoUtils.getBuildDateTimestamp())); DateFormat.LONG, BuildInfoUtils.getBuildDateTimestamp()));
if (!mIsTV) { if (!mIsTV) {
// Switch between header title and appbar title minimizing overlaps // Switch between header title and appbar title minimizing overlaps
final CollapsingToolbarLayout collapsingToolbar = final CollapsingToolbarLayout collapsingToolbar = findViewById(R.id.collapsing_toolbar);
(CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar); final AppBarLayout appBar = findViewById(R.id.app_bar);
final AppBarLayout appBar = (AppBarLayout) findViewById(R.id.app_bar);
appBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { appBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
boolean mIsShown = false; boolean mIsShown = false;
@@ -175,18 +177,8 @@ public class UpdatesActivity extends UpdatesListActivity {
appBar.setExpanded(false); appBar.setExpanded(false);
} }
} else { } else {
findViewById(R.id.refresh).setOnClickListener(new View.OnClickListener() { findViewById(R.id.refresh).setOnClickListener(v -> downloadUpdatesList(true));
@Override findViewById(R.id.preferences).setOnClickListener(v -> showPreferencesDialog());
public void onClick(View v) {
downloadUpdatesList(true);
}
});
findViewById(R.id.preferences).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showPreferencesDialog();
}
});
} }
} }
@@ -222,21 +214,18 @@ public class UpdatesActivity extends UpdatesListActivity {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { int itemId = item.getItemId();
case R.id.menu_refresh: { if (itemId == R.id.menu_refresh) {
downloadUpdatesList(true); downloadUpdatesList(true);
return true; return true;
} } else if (itemId == R.id.menu_preferences) {
case R.id.menu_preferences: { showPreferencesDialog();
showPreferencesDialog(); return true;
return true; } else if (itemId == R.id.menu_show_changelog) {
} Intent openUrl = new Intent(Intent.ACTION_VIEW,
case R.id.menu_show_changelog: { Uri.parse(Utils.getChangelogURL(this)));
Intent openUrl = new Intent(Intent.ACTION_VIEW, startActivity(openUrl);
Uri.parse(Utils.getChangelogURL(this))); return true;
startActivity(openUrl);
return true;
}
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@@ -247,7 +236,7 @@ public class UpdatesActivity extends UpdatesListActivity {
return true; return true;
} }
private ServiceConnection mConnection = new ServiceConnection() { private final ServiceConnection mConnection = new ServiceConnection() {
@Override @Override
public void onServiceConnected(ComponentName className, public void onServiceConnected(ComponentName className,
@@ -330,6 +319,7 @@ public class UpdatesActivity extends UpdatesListActivity {
} }
// In case we set a one-shot check because of a previous failure // In case we set a one-shot check because of a previous failure
UpdatesCheckReceiver.cancelUpdatesCheck(this); UpdatesCheckReceiver.cancelUpdatesCheck(this);
//noinspection ResultOfMethodCallIgnored
jsonNew.renameTo(json); jsonNew.renameTo(json);
} catch (IOException | JSONException e) { } catch (IOException | JSONException e) {
Log.e(TAG, "Could not read json", e); Log.e(TAG, "Could not read json", e);
@@ -356,12 +346,11 @@ public class UpdatesActivity extends UpdatesListActivity {
} }
@Override @Override
public void onResponse(int statusCode, String url, public void onResponse(DownloadClient.Headers headers) {
DownloadClient.Headers headers) {
} }
@Override @Override
public void onSuccess(File destination) { public void onSuccess() {
runOnUiThread(() -> { runOnUiThread(() -> {
Log.d(TAG, "List downloaded"); Log.d(TAG, "List downloaded");
processNewJson(jsonFile, jsonFileTmp, manualRefresh); processNewJson(jsonFile, jsonFileTmp, manualRefresh);
@@ -394,7 +383,7 @@ public class UpdatesActivity extends UpdatesListActivity {
String lastCheckString = getString(R.string.header_last_updates_check, String lastCheckString = getString(R.string.header_last_updates_check,
StringGenerator.getDateLocalized(this, DateFormat.LONG, lastCheck), StringGenerator.getDateLocalized(this, DateFormat.LONG, lastCheck),
StringGenerator.getTimeLocalized(this, lastCheck)); StringGenerator.getTimeLocalized(this, lastCheck));
TextView headerLastCheck = (TextView) findViewById(R.id.header_last_check); TextView headerLastCheck = findViewById(R.id.header_last_check);
headerLastCheck.setText(lastCheckString); headerLastCheck.setText(lastCheckString);
} }
@@ -451,14 +440,14 @@ public class UpdatesActivity extends UpdatesListActivity {
} }
} }
@SuppressLint("ClickableViewAccessibility")
private void showPreferencesDialog() { private void showPreferencesDialog() {
View view = LayoutInflater.from(this).inflate(R.layout.preferences_dialog, null); View view = LayoutInflater.from(this).inflate(R.layout.preferences_dialog, null);
Spinner autoCheckInterval = Spinner autoCheckInterval = view.findViewById(R.id.preferences_auto_updates_check_interval);
view.findViewById(R.id.preferences_auto_updates_check_interval); SwitchCompat autoDelete = view.findViewById(R.id.preferences_auto_delete_updates);
Switch autoDelete = view.findViewById(R.id.preferences_auto_delete_updates); SwitchCompat dataWarning = view.findViewById(R.id.preferences_mobile_data_warning);
Switch dataWarning = view.findViewById(R.id.preferences_mobile_data_warning); SwitchCompat abPerfMode = view.findViewById(R.id.preferences_ab_perf_mode);
Switch abPerfMode = view.findViewById(R.id.preferences_ab_perf_mode); SwitchCompat updateRecovery = view.findViewById(R.id.preferences_update_recovery);
Switch updateRecovery = view.findViewById(R.id.preferences_update_recovery);
if (!Utils.isABDevice()) { if (!Utils.isABDevice()) {
abPerfMode.setVisibility(View.GONE); abPerfMode.setVisibility(View.GONE);
@@ -471,7 +460,7 @@ public class UpdatesActivity extends UpdatesListActivity {
abPerfMode.setChecked(prefs.getBoolean(Constants.PREF_AB_PERF_MODE, false)); abPerfMode.setChecked(prefs.getBoolean(Constants.PREF_AB_PERF_MODE, false));
if (getResources().getBoolean(R.bool.config_hideRecoveryUpdate)) { if (getResources().getBoolean(R.bool.config_hideRecoveryUpdate)) {
// Hide the update feature if explicitely requested. // Hide the update feature if explicitly requested.
// Might be the case of A-only devices using prebuilt vendor images. // Might be the case of A-only devices using prebuilt vendor images.
updateRecovery.setVisibility(View.GONE); updateRecovery.setVisibility(View.GONE);
} else if (Utils.isRecoveryUpdateExecPresent()) { } else if (Utils.isRecoveryUpdateExecPresent()) {
@@ -505,12 +494,9 @@ public class UpdatesActivity extends UpdatesListActivity {
prefs.edit() prefs.edit()
.putInt(Constants.PREF_AUTO_UPDATES_CHECK_INTERVAL, .putInt(Constants.PREF_AUTO_UPDATES_CHECK_INTERVAL,
autoCheckInterval.getSelectedItemPosition()) autoCheckInterval.getSelectedItemPosition())
.putBoolean(Constants.PREF_AUTO_DELETE_UPDATES, .putBoolean(Constants.PREF_AUTO_DELETE_UPDATES, autoDelete.isChecked())
autoDelete.isChecked()) .putBoolean(Constants.PREF_MOBILE_DATA_WARNING, dataWarning.isChecked())
.putBoolean(Constants.PREF_MOBILE_DATA_WARNING, .putBoolean(Constants.PREF_AB_PERF_MODE, abPerfMode.isChecked())
dataWarning.isChecked())
.putBoolean(Constants.PREF_AB_PERF_MODE,
abPerfMode.isChecked())
.apply(); .apply();
if (Utils.isUpdateCheckEnabled(this)) { if (Utils.isUpdateCheckEnabled(this)) {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -84,17 +84,17 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
} }
@Override @Override
public void onResponse(int statusCode, String url, public void onResponse(DownloadClient.Headers headers) {
DownloadClient.Headers headers) {
} }
@Override @Override
public void onSuccess(File destination) { public void onSuccess() {
try { try {
if (json.exists() && Utils.checkForNewUpdates(json, jsonNew)) { if (json.exists() && Utils.checkForNewUpdates(json, jsonNew)) {
showNotification(context); showNotification(context);
updateRepeatingUpdatesCheck(context); updateRepeatingUpdatesCheck(context);
} }
//noinspection ResultOfMethodCallIgnored
jsonNew.renameTo(json); jsonNew.renameTo(json);
long currentMillis = System.currentTimeMillis(); long currentMillis = System.currentTimeMillis();
preferences.edit() preferences.edit()
@@ -123,8 +123,8 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
} }
private static void showNotification(Context context) { private static void showNotification(Context context) {
NotificationManager notificationManager = NotificationManager notificationManager = context.getSystemService(
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager.class);
NotificationChannel notificationChannel = new NotificationChannel( NotificationChannel notificationChannel = new NotificationChannel(
NEW_UPDATES_NOTIFICATION_CHANNEL, NEW_UPDATES_NOTIFICATION_CHANNEL,
context.getString(R.string.new_updates_channel_title), context.getString(R.string.new_updates_channel_title),
@@ -159,7 +159,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
} }
PendingIntent updateCheckIntent = getRepeatingUpdatesCheckIntent(context); PendingIntent updateCheckIntent = getRepeatingUpdatesCheckIntent(context);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
alarmMgr.setRepeating(AlarmManager.RTC, System.currentTimeMillis() + alarmMgr.setRepeating(AlarmManager.RTC, System.currentTimeMillis() +
Utils.getUpdateCheckInterval(context), Utils.getUpdateCheckInterval(context), Utils.getUpdateCheckInterval(context), Utils.getUpdateCheckInterval(context),
updateCheckIntent); updateCheckIntent);
@@ -170,7 +170,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
} }
public static void cancelRepeatingUpdatesCheck(Context context) { public static void cancelRepeatingUpdatesCheck(Context context) {
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
alarmMgr.cancel(getRepeatingUpdatesCheckIntent(context)); alarmMgr.cancel(getRepeatingUpdatesCheckIntent(context));
} }
@@ -183,7 +183,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
public static void scheduleUpdatesCheck(Context context) { public static void scheduleUpdatesCheck(Context context) {
long millisToNextCheck = AlarmManager.INTERVAL_HOUR * 2; long millisToNextCheck = AlarmManager.INTERVAL_HOUR * 2;
PendingIntent updateCheckIntent = getUpdatesCheckIntent(context); PendingIntent updateCheckIntent = getUpdatesCheckIntent(context);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME, alarmMgr.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + millisToNextCheck, SystemClock.elapsedRealtime() + millisToNextCheck,
updateCheckIntent); updateCheckIntent);
@@ -193,7 +193,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
} }
public static void cancelUpdatesCheck(Context context) { public static void cancelUpdatesCheck(Context context) {
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
alarmMgr.cancel(getUpdatesCheckIntent(context)); alarmMgr.cancel(getUpdatesCheckIntent(context));
Log.d(TAG, "Cancelling pending one-shot check"); Log.d(TAG, "Cancelling pending one-shot check");
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -75,18 +75,11 @@ public class UpdatesDbHelper extends SQLiteOpenHelper {
onUpgrade(db, oldVersion, newVersion); onUpgrade(db, oldVersion, newVersion);
} }
public long addUpdate(Update update) { public void addUpdateWithOnConflict(Update update, int conflictAlgorithm) {
SQLiteDatabase db = getWritableDatabase(); SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
fillContentValues(update, values); fillContentValues(update, values);
return db.insert(UpdateEntry.TABLE_NAME, null, values); db.insertWithOnConflict(UpdateEntry.TABLE_NAME, null, values, conflictAlgorithm);
}
public long addUpdateWithOnConflict(Update update, int conflictAlgorithm) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
fillContentValues(update, values);
return db.insertWithOnConflict(UpdateEntry.TABLE_NAME, null, values, conflictAlgorithm);
} }
private static void fillContentValues(Update update, ContentValues values) { private static void fillContentValues(Update update, ContentValues values) {
@@ -99,52 +92,25 @@ public class UpdatesDbHelper extends SQLiteOpenHelper {
values.put(UpdateEntry.COLUMN_NAME_SIZE, update.getFileSize()); values.put(UpdateEntry.COLUMN_NAME_SIZE, update.getFileSize());
} }
public boolean removeUpdate(String downloadId) { public void removeUpdate(String downloadId) {
SQLiteDatabase db = getWritableDatabase(); SQLiteDatabase db = getWritableDatabase();
String selection = UpdateEntry.COLUMN_NAME_DOWNLOAD_ID + " = ?"; String selection = UpdateEntry.COLUMN_NAME_DOWNLOAD_ID + " = ?";
String[] selectionArgs = {downloadId}; String[] selectionArgs = {downloadId};
return db.delete(UpdateEntry.TABLE_NAME, selection, selectionArgs) != 0; db.delete(UpdateEntry.TABLE_NAME, selection, selectionArgs);
} }
public boolean removeUpdate(long rowId) { public void changeUpdateStatus(Update update) {
SQLiteDatabase db = getWritableDatabase();
String selection = UpdateEntry._ID + " = " + rowId;
return db.delete(UpdateEntry.TABLE_NAME, selection, null) != 0;
}
public boolean changeUpdateStatus(Update update) {
String selection = UpdateEntry.COLUMN_NAME_DOWNLOAD_ID + " = ?"; String selection = UpdateEntry.COLUMN_NAME_DOWNLOAD_ID + " = ?";
String[] selectionArgs = {update.getDownloadId()}; String[] selectionArgs = {update.getDownloadId()};
return changeUpdateStatus(selection, selectionArgs, update.getPersistentStatus()); changeUpdateStatus(selection, selectionArgs, update.getPersistentStatus());
} }
public boolean changeUpdateStatus(long rowId, int status) { private void changeUpdateStatus(String selection, String[] selectionArgs,
String selection = UpdateEntry._ID + " = " + rowId; int status) {
return changeUpdateStatus(selection, null, status);
}
private boolean changeUpdateStatus(String selection, String[] selectionArgs,
int status) {
SQLiteDatabase db = getWritableDatabase(); SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(UpdateEntry.COLUMN_NAME_STATUS, status); values.put(UpdateEntry.COLUMN_NAME_STATUS, status);
return db.update(UpdateEntry.TABLE_NAME, values, selection, selectionArgs) != 0; db.update(UpdateEntry.TABLE_NAME, values, selection, selectionArgs);
}
public Update getUpdate(long rowId) {
String selection = UpdateEntry._ID + " = " + rowId;
return getUpdate(selection, null);
}
public Update getUpdate(String downloadId) {
String selection = UpdateEntry.COLUMN_NAME_DOWNLOAD_ID + " = ?";
String[] selectionArgs = {downloadId};
return getUpdate(selection, selectionArgs);
}
private Update getUpdate(String selection, String[] selectionArgs) {
List<Update> updates = getUpdates(selection, selectionArgs);
return updates != null ? updates.get(0) : null;
} }
public List<Update> getUpdates() { public List<Update> getUpdates() {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
*/ */
package org.lineageos.updater; package org.lineageos.updater;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@@ -39,6 +38,7 @@ import android.widget.ImageButton;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ContextThemeWrapper; import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.view.menu.MenuBuilder; import androidx.appcompat.view.menu.MenuBuilder;
@@ -77,7 +77,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
private List<String> mDownloadIds; private List<String> mDownloadIds;
private String mSelectedDownload; private String mSelectedDownload;
private UpdaterController mUpdaterController; private UpdaterController mUpdaterController;
private UpdatesListActivity mActivity; private final UpdatesListActivity mActivity;
private AlertDialog infoDialog; private AlertDialog infoDialog;
@@ -93,27 +93,27 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
private Button mAction; private final Button mAction;
private ImageButton mMenu; private final ImageButton mMenu;
private TextView mBuildDate; private final TextView mBuildDate;
private TextView mBuildVersion; private final TextView mBuildVersion;
private TextView mBuildSize; private final TextView mBuildSize;
private ProgressBar mProgressBar; private final ProgressBar mProgressBar;
private TextView mProgressText; private final TextView mProgressText;
public ViewHolder(final View view) { public ViewHolder(final View view) {
super(view); super(view);
mAction = (Button) view.findViewById(R.id.update_action); mAction = view.findViewById(R.id.update_action);
mMenu = (ImageButton) view.findViewById(R.id.update_menu); mMenu = view.findViewById(R.id.update_menu);
mBuildDate = (TextView) view.findViewById(R.id.build_date); mBuildDate = view.findViewById(R.id.build_date);
mBuildVersion = (TextView) view.findViewById(R.id.build_version); mBuildVersion = view.findViewById(R.id.build_version);
mBuildSize = (TextView) view.findViewById(R.id.build_size); mBuildSize = view.findViewById(R.id.build_size);
mProgressBar = (ProgressBar) view.findViewById(R.id.progress_bar); mProgressBar = view.findViewById(R.id.progress_bar);
mProgressText = (TextView) view.findViewById(R.id.progress_text); mProgressText = view.findViewById(R.id.progress_text);
} }
} }
@@ -125,6 +125,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
mAlphaDisabledValue = tv.getFloat(); mAlphaDisabledValue = tv.getFloat();
} }
@NonNull
@Override @Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()) View view = LayoutInflater.from(viewGroup.getContext())
@@ -133,7 +134,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
} }
@Override @Override
public void onViewDetachedFromWindow(ViewHolder holder) { public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder); super.onViewDetachedFromWindow(holder);
if (infoDialog != null) { if (infoDialog != null) {
@@ -191,8 +192,8 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
String total = Formatter.formatShortFileSize(mActivity, update.getFileSize()); String total = Formatter.formatShortFileSize(mActivity, update.getFileSize());
String percentage = NumberFormat.getPercentInstance().format( String percentage = NumberFormat.getPercentInstance().format(
update.getProgress() / 100.f); update.getProgress() / 100.f);
viewHolder.mProgressText.setText(mActivity.getString(R.string.list_download_progress_new, viewHolder.mProgressText.setText(mActivity.getString(
downloaded, total, percentage)); R.string.list_download_progress_new, downloaded, total, percentage));
viewHolder.mProgressBar.setIndeterminate(false); viewHolder.mProgressBar.setIndeterminate(false);
viewHolder.mProgressBar.setProgress(update.getProgress()); viewHolder.mProgressBar.setProgress(update.getProgress());
} }
@@ -229,7 +230,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
} }
@Override @Override
public void onBindViewHolder(final ViewHolder viewHolder, int i) { public void onBindViewHolder(@NonNull final ViewHolder viewHolder, int i) {
if (mDownloadIds == null) { if (mDownloadIds == null) {
viewHolder.mAction.setEnabled(false); viewHolder.mAction.setEnabled(false);
return; return;
@@ -311,7 +312,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
} }
View checkboxView = LayoutInflater.from(mActivity).inflate(R.layout.checkbox_view, null); View checkboxView = LayoutInflater.from(mActivity).inflate(R.layout.checkbox_view, null);
CheckBox checkbox = (CheckBox) checkboxView.findViewById(R.id.checkbox); CheckBox checkbox = checkboxView.findViewById(R.id.checkbox);
checkbox.setText(R.string.checkbox_mobile_data_warning); checkbox.setText(R.string.checkbox_mobile_data_warning);
new AlertDialog.Builder(mActivity) new AlertDialog.Builder(mActivity)
@@ -370,7 +371,10 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
final boolean canInstall = Utils.canInstall(update); final boolean canInstall = Utils.canInstall(update);
clickListener = enabled ? view -> { clickListener = enabled ? view -> {
if (canInstall) { if (canInstall) {
getInstallDialog(downloadId).show(); AlertDialog.Builder installDialog = getInstallDialog(downloadId);
if (installDialog != null) {
installDialog.show();
}
} else { } else {
mActivity.showSnackbar(R.string.snack_update_not_installable, mActivity.showSnackbar(R.string.snack_update_not_installable,
Snackbar.LENGTH_LONG); Snackbar.LENGTH_LONG);
@@ -400,8 +404,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
button.setText(R.string.reboot); button.setText(R.string.reboot);
button.setEnabled(enabled); button.setEnabled(enabled);
clickListener = enabled ? view -> { clickListener = enabled ? view -> {
PowerManager pm = PowerManager pm = mActivity.getSystemService(PowerManager.class);
(PowerManager) mActivity.getSystemService(Context.POWER_SERVICE);
pm.reboot(null); pm.reboot(null);
} : null; } : null;
} }
@@ -438,9 +441,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
private View.OnClickListener getClickListener(final UpdateInfo update, private View.OnClickListener getClickListener(final UpdateInfo update,
final boolean canDelete, View anchor) { final boolean canDelete, View anchor) {
return view -> { return view -> startActionMode(update, canDelete, anchor);
startActionMode(update, canDelete, anchor);
};
} }
private AlertDialog.Builder getInstallDialog(final String downloadId) { private AlertDialog.Builder getInstallDialog(final String downloadId) {
@@ -509,24 +510,24 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
update.getPersistentStatus() == UpdateStatus.Persistent.VERIFIED); update.getPersistentStatus() == UpdateStatus.Persistent.VERIFIED);
popupMenu.setOnMenuItemClickListener(item -> { popupMenu.setOnMenuItemClickListener(item -> {
switch (item.getItemId()) { int itemId = item.getItemId();
case R.id.menu_delete_action: if (itemId == R.id.menu_delete_action) {
getDeleteDialog(update.getDownloadId()).show(); getDeleteDialog(update.getDownloadId()).show();
return true; return true;
case R.id.menu_copy_url: } else if (itemId == R.id.menu_copy_url) {
Utils.addToClipboard(mActivity, Utils.addToClipboard(mActivity,
mActivity.getString(R.string.label_download_url), mActivity.getString(R.string.label_download_url),
update.getDownloadUrl(), update.getDownloadUrl(),
mActivity.getString(R.string.toast_download_url_copied)); mActivity.getString(R.string.toast_download_url_copied));
return true; return true;
case R.id.menu_export_update: } else if (itemId == R.id.menu_export_update) {
// TODO: start exporting once the permission has been granted // TODO: start exporting once the permission has been granted
boolean hasPermission = PermissionsUtils.checkAndRequestStoragePermission( boolean hasPermission = PermissionsUtils.checkAndRequestStoragePermission(
mActivity, 0); mActivity, 0);
if (hasPermission) { if (hasPermission) {
exportUpdate(update); exportUpdate(update);
} }
return true; return true;
} }
return false; return false;
}); });
@@ -561,8 +562,10 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
.setPositiveButton(android.R.string.ok, null) .setPositiveButton(android.R.string.ok, null)
.setMessage(message) .setMessage(message)
.show(); .show();
TextView textView = (TextView) infoDialog.findViewById(android.R.id.message); TextView textView = infoDialog.findViewById(android.R.id.message);
textView.setMovementMethod(LinkMovementMethod.getInstance()); if (textView != null) {
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
} }
private boolean isBatteryLevelOk() { private boolean isBatteryLevelOk() {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ class ABUpdateInstaller {
private final Context mContext; private final Context mContext;
private String mDownloadId; private String mDownloadId;
private UpdateEngine mUpdateEngine; private final UpdateEngine mUpdateEngine;
private boolean mBound; private boolean mBound;
private boolean mFinalizing; private boolean mFinalizing;
@@ -130,11 +130,6 @@ class ABUpdateInstaller {
return pref.getString(ABUpdateInstaller.PREF_INSTALLING_SUSPENDED_AB_ID, null) != null; return pref.getString(ABUpdateInstaller.PREF_INSTALLING_SUSPENDED_AB_ID, null) != null;
} }
static synchronized boolean isInstallingUpdateSuspended(Context context, String downloadId) {
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
return downloadId.equals(pref.getString(ABUpdateInstaller.PREF_INSTALLING_SUSPENDED_AB_ID, null));
}
static synchronized boolean isWaitingForReboot(Context context, String downloadId) { static synchronized boolean isWaitingForReboot(Context context, String downloadId) {
String waitingId = PreferenceManager.getDefaultSharedPreferences(context) String waitingId = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.PREF_NEEDS_REBOOT_ID, null); .getString(Constants.PREF_NEEDS_REBOOT_ID, null);
@@ -155,10 +150,10 @@ class ABUpdateInstaller {
return sInstance; return sInstance;
} }
public boolean install(String downloadId) { public void install(String downloadId) {
if (isInstallingUpdate(mContext)) { if (isInstallingUpdate(mContext)) {
Log.e(TAG, "Already installing an update"); Log.e(TAG, "Already installing an update");
return false; return;
} }
mDownloadId = downloadId; mDownloadId = downloadId;
@@ -169,7 +164,7 @@ class ABUpdateInstaller {
mUpdaterController.getActualUpdate(downloadId) mUpdaterController.getActualUpdate(downloadId)
.setStatus(UpdateStatus.INSTALLATION_FAILED); .setStatus(UpdateStatus.INSTALLATION_FAILED);
mUpdaterController.notifyUpdateChange(downloadId); mUpdaterController.notifyUpdateChange(downloadId);
return false; return;
} }
long offset; long offset;
@@ -194,7 +189,7 @@ class ABUpdateInstaller {
mUpdaterController.getActualUpdate(mDownloadId) mUpdaterController.getActualUpdate(mDownloadId)
.setStatus(UpdateStatus.INSTALLATION_FAILED); .setStatus(UpdateStatus.INSTALLATION_FAILED);
mUpdaterController.notifyUpdateChange(mDownloadId); mUpdaterController.notifyUpdateChange(mDownloadId);
return false; return;
} }
if (!mBound) { if (!mBound) {
@@ -204,7 +199,7 @@ class ABUpdateInstaller {
mUpdaterController.getActualUpdate(downloadId) mUpdaterController.getActualUpdate(downloadId)
.setStatus(UpdateStatus.INSTALLATION_FAILED); .setStatus(UpdateStatus.INSTALLATION_FAILED);
mUpdaterController.notifyUpdateChange(downloadId); mUpdaterController.notifyUpdateChange(downloadId);
return false; return;
} }
} }
@@ -222,17 +217,16 @@ class ABUpdateInstaller {
.putString(PREF_INSTALLING_AB_ID, mDownloadId) .putString(PREF_INSTALLING_AB_ID, mDownloadId)
.apply(); .apply();
return true;
} }
public boolean reconnect() { public void reconnect() {
if (!isInstallingUpdate(mContext)) { if (!isInstallingUpdate(mContext)) {
Log.e(TAG, "reconnect: Not installing any update"); Log.e(TAG, "reconnect: Not installing any update");
return false; return;
} }
if (mBound) { if (mBound) {
return true; return;
} }
mDownloadId = PreferenceManager.getDefaultSharedPreferences(mContext) mDownloadId = PreferenceManager.getDefaultSharedPreferences(mContext)
@@ -242,10 +236,8 @@ class ABUpdateInstaller {
mBound = mUpdateEngine.bind(mUpdateEngineCallback); mBound = mUpdateEngine.bind(mUpdateEngineCallback);
if (!mBound) { if (!mBound) {
Log.e(TAG, "Could not bind"); Log.e(TAG, "Could not bind");
return false;
} }
return true;
} }
private void installationDone(boolean needsReboot) { private void installationDone(boolean needsReboot) {
@@ -257,15 +249,15 @@ class ABUpdateInstaller {
.apply(); .apply();
} }
public boolean cancel() { public void cancel() {
if (!isInstallingUpdate(mContext)) { if (!isInstallingUpdate(mContext)) {
Log.e(TAG, "cancel: Not installing any update"); Log.e(TAG, "cancel: Not installing any update");
return false; return;
} }
if (!mBound) { if (!mBound) {
Log.e(TAG, "Not connected to update engine"); Log.e(TAG, "Not connected to update engine");
return false; return;
} }
mUpdateEngine.cancel(); mUpdateEngine.cancel();
@@ -275,22 +267,21 @@ class ABUpdateInstaller {
.setStatus(UpdateStatus.INSTALLATION_CANCELLED); .setStatus(UpdateStatus.INSTALLATION_CANCELLED);
mUpdaterController.notifyUpdateChange(mDownloadId); mUpdaterController.notifyUpdateChange(mDownloadId);
return true;
} }
public void setPerformanceMode(boolean enable) { public void setPerformanceMode(boolean enable) {
mUpdateEngine.setPerformanceMode(enable); mUpdateEngine.setPerformanceMode(enable);
} }
public boolean suspend() { public void suspend() {
if (!isInstallingUpdate(mContext)) { if (!isInstallingUpdate(mContext)) {
Log.e(TAG, "cancel: Not installing any update"); Log.e(TAG, "cancel: Not installing any update");
return false; return;
} }
if (!mBound) { if (!mBound) {
Log.e(TAG, "Not connected to update engine"); Log.e(TAG, "Not connected to update engine");
return false; return;
} }
mUpdateEngine.suspend(); mUpdateEngine.suspend();
@@ -303,18 +294,17 @@ class ABUpdateInstaller {
.putString(PREF_INSTALLING_SUSPENDED_AB_ID, mDownloadId) .putString(PREF_INSTALLING_SUSPENDED_AB_ID, mDownloadId)
.apply(); .apply();
return true;
} }
public boolean resume() { public void resume() {
if (!isInstallingUpdateSuspended(mContext)) { if (!isInstallingUpdateSuspended(mContext)) {
Log.e(TAG, "cancel: No update is suspended"); Log.e(TAG, "cancel: No update is suspended");
return false; return;
} }
if (!mBound) { if (!mBound) {
Log.e(TAG, "Not connected to update engine"); Log.e(TAG, "Not connected to update engine");
return false; return;
} }
mUpdateEngine.resume(); mUpdateEngine.resume();
@@ -329,6 +319,5 @@ class ABUpdateInstaller {
.remove(PREF_INSTALLING_SUSPENDED_AB_ID) .remove(PREF_INSTALLING_SUSPENDED_AB_ID)
.apply(); .apply();
return true;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -113,7 +113,7 @@ class UpdateInstaller {
Runnable copyUpdateRunnable = new Runnable() { Runnable copyUpdateRunnable = new Runnable() {
private long mLastUpdate = -1; private long mLastUpdate = -1;
FileUtils.ProgressCallBack mProgressCallBack = new FileUtils.ProgressCallBack() { final FileUtils.ProgressCallBack mProgressCallBack = new FileUtils.ProgressCallBack() {
@Override @Override
public void update(int progress) { public void update(int progress) {
long now = SystemClock.elapsedRealtime(); long now = SystemClock.elapsedRealtime();
@@ -137,12 +137,14 @@ class UpdateInstaller {
.setStatus(UpdateStatus.INSTALLATION_CANCELLED); .setStatus(UpdateStatus.INSTALLATION_CANCELLED);
mUpdaterController.getActualUpdate(update.getDownloadId()) mUpdaterController.getActualUpdate(update.getDownloadId())
.setInstallProgress(0); .setInstallProgress(0);
//noinspection ResultOfMethodCallIgnored
uncryptFile.delete(); uncryptFile.delete();
} else { } else {
installPackage(uncryptFile, update.getDownloadId()); installPackage(uncryptFile, update.getDownloadId());
} }
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Could not copy update", e); Log.e(TAG, "Could not copy update", e);
//noinspection ResultOfMethodCallIgnored
uncryptFile.delete(); uncryptFile.delete();
mUpdaterController.getActualUpdate(update.getDownloadId()) mUpdaterController.getActualUpdate(update.getDownloadId())
.setStatus(UpdateStatus.INSTALLATION_FAILED); .setStatus(UpdateStatus.INSTALLATION_FAILED);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/ */
package org.lineageos.updater.controller; package org.lineageos.updater.controller;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
@@ -63,11 +64,7 @@ public class UpdaterController {
private final File mDownloadRoot; private final File mDownloadRoot;
private int mActiveDownloads = 0; private int mActiveDownloads = 0;
private Set<String> mVerifyingUpdates = new HashSet<>(); private final Set<String> mVerifyingUpdates = new HashSet<>();
public static synchronized UpdaterController getInstance() {
return sUpdaterController;
}
protected static synchronized UpdaterController getInstance(Context context) { protected static synchronized UpdaterController getInstance(Context context) {
if (sUpdaterController == null) { if (sUpdaterController == null) {
@@ -80,8 +77,8 @@ public class UpdaterController {
mBroadcastManager = LocalBroadcastManager.getInstance(context); mBroadcastManager = LocalBroadcastManager.getInstance(context);
mUpdatesDbHelper = new UpdatesDbHelper(context); mUpdatesDbHelper = new UpdatesDbHelper(context);
mDownloadRoot = Utils.getDownloadPath(context); mDownloadRoot = Utils.getDownloadPath(context);
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager powerManager = context.getSystemService(PowerManager.class);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Updater"); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Updater:wakelock");
mWakeLock.setReferenceCounted(false); mWakeLock.setReferenceCounted(false);
mContext = context.getApplicationContext(); mContext = context.getApplicationContext();
@@ -92,7 +89,7 @@ public class UpdaterController {
} }
} }
private class DownloadEntry { private static class DownloadEntry {
final Update mUpdate; final Update mUpdate;
DownloadClient mDownloadClient; DownloadClient mDownloadClient;
private DownloadEntry(Update update) { private DownloadEntry(Update update) {
@@ -100,7 +97,7 @@ public class UpdaterController {
} }
} }
private Map<String, DownloadEntry> mDownloads = new HashMap<>(); private final Map<String, DownloadEntry> mDownloads = new HashMap<>();
void notifyUpdateChange(String downloadId) { void notifyUpdateChange(String downloadId) {
Intent intent = new Intent(); Intent intent = new Intent();
@@ -156,8 +153,12 @@ public class UpdaterController {
return new DownloadClient.DownloadCallback() { return new DownloadClient.DownloadCallback() {
@Override @Override
public void onResponse(int statusCode, String url, DownloadClient.Headers headers) { public void onResponse(DownloadClient.Headers headers) {
final Update update = mDownloads.get(downloadId).mUpdate; final DownloadEntry entry = mDownloads.get(downloadId);
if (entry == null) {
return;
}
final Update update = entry.mUpdate;
String contentLength = headers.get("Content-Length"); String contentLength = headers.get("Content-Length");
if (contentLength != null) { if (contentLength != null) {
try { try {
@@ -177,27 +178,33 @@ public class UpdaterController {
} }
@Override @Override
public void onSuccess(File destination) { public void onSuccess() {
Log.d(TAG, "Download complete"); Log.d(TAG, "Download complete");
Update update = mDownloads.get(downloadId).mUpdate; DownloadEntry entry = mDownloads.get(downloadId);
update.setStatus(UpdateStatus.VERIFYING); if (entry != null) {
removeDownloadClient(mDownloads.get(downloadId)); Update update = entry.mUpdate;
verifyUpdateAsync(downloadId); update.setStatus(UpdateStatus.VERIFYING);
notifyUpdateChange(downloadId); removeDownloadClient(entry);
tryReleaseWakelock(); verifyUpdateAsync(downloadId);
notifyUpdateChange(downloadId);
tryReleaseWakelock();
}
} }
@Override @Override
public void onFailure(boolean cancelled) { public void onFailure(boolean cancelled) {
Update update = mDownloads.get(downloadId).mUpdate;
if (cancelled) { if (cancelled) {
Log.d(TAG, "Download cancelled"); Log.d(TAG, "Download cancelled");
// Already notified // Already notified
} else { } else {
Log.e(TAG, "Download failed"); DownloadEntry entry = mDownloads.get(downloadId);
removeDownloadClient(mDownloads.get(downloadId)); if (entry != null) {
update.setStatus(UpdateStatus.PAUSED_ERROR); Update update = entry.mUpdate;
notifyUpdateChange(downloadId); Log.e(TAG, "Download failed");
removeDownloadClient(entry);
update.setStatus(UpdateStatus.PAUSED_ERROR);
notifyUpdateChange(downloadId);
}
} }
tryReleaseWakelock(); tryReleaseWakelock();
} }
@@ -210,9 +217,12 @@ public class UpdaterController {
private int mProgress = 0; private int mProgress = 0;
@Override @Override
public void update(long bytesRead, long contentLength, long speed, long eta, public void update(long bytesRead, long contentLength, long speed, long eta) {
boolean done) { DownloadEntry entry = mDownloads.get(downloadId);
Update update = mDownloads.get(downloadId).mUpdate; if (entry == null) {
return;
}
Update update = entry.mUpdate;
if (contentLength <= 0) { if (contentLength <= 0) {
if (update.getFileSize() <= 0) { if (update.getFileSize() <= 0) {
return; return;
@@ -224,7 +234,7 @@ public class UpdaterController {
return; return;
} }
final long now = SystemClock.elapsedRealtime(); final long now = SystemClock.elapsedRealtime();
int progress = Math.round(bytesRead * 100 / contentLength); int progress = Math.round(bytesRead * 100f / contentLength);
if (progress != mProgress || mLastUpdate - now > MAX_REPORT_INTERVAL_MS) { if (progress != mProgress || mLastUpdate - now > MAX_REPORT_INTERVAL_MS) {
mProgress = progress; mProgress = progress;
mLastUpdate = now; mLastUpdate = now;
@@ -237,24 +247,29 @@ public class UpdaterController {
}; };
} }
@SuppressLint("SetWorldReadable")
private void verifyUpdateAsync(final String downloadId) { private void verifyUpdateAsync(final String downloadId) {
mVerifyingUpdates.add(downloadId); mVerifyingUpdates.add(downloadId);
new Thread(() -> { new Thread(() -> {
Update update = mDownloads.get(downloadId).mUpdate; DownloadEntry entry = mDownloads.get(downloadId);
File file = update.getFile(); if (entry != null) {
if (file.exists() && verifyPackage(file)) { Update update = entry.mUpdate;
file.setReadable(true, false); File file = update.getFile();
update.setPersistentStatus(UpdateStatus.Persistent.VERIFIED); if (file.exists() && verifyPackage(file)) {
mUpdatesDbHelper.changeUpdateStatus(update); //noinspection ResultOfMethodCallIgnored
update.setStatus(UpdateStatus.VERIFIED); file.setReadable(true, false);
} else { update.setPersistentStatus(UpdateStatus.Persistent.VERIFIED);
update.setPersistentStatus(UpdateStatus.Persistent.UNKNOWN); mUpdatesDbHelper.changeUpdateStatus(update);
mUpdatesDbHelper.removeUpdate(downloadId); update.setStatus(UpdateStatus.VERIFIED);
update.setProgress(0); } else {
update.setStatus(UpdateStatus.VERIFICATION_FAILED); update.setPersistentStatus(UpdateStatus.Persistent.UNKNOWN);
mUpdatesDbHelper.removeUpdate(downloadId);
update.setProgress(0);
update.setStatus(UpdateStatus.VERIFICATION_FAILED);
}
mVerifyingUpdates.remove(downloadId);
notifyUpdateChange(downloadId);
} }
mVerifyingUpdates.remove(downloadId);
notifyUpdateChange(downloadId);
}).start(); }).start();
} }
@@ -266,6 +281,7 @@ public class UpdaterController {
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Verification failed", e); Log.e(TAG, "Verification failed", e);
if (file.exists()) { if (file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.delete(); file.delete();
} else { } else {
// The download was probably stopped. Exit silently // The download was probably stopped. Exit silently
@@ -285,7 +301,7 @@ public class UpdaterController {
} else if (update.getFileSize() > 0) { } else if (update.getFileSize() > 0) {
update.setStatus(UpdateStatus.PAUSED); update.setStatus(UpdateStatus.PAUSED);
int progress = Math.round( int progress = Math.round(
update.getFile().length() * 100 / update.getFileSize()); update.getFile().length() * 100f / update.getFileSize());
update.setProgress(progress); update.setProgress(progress);
} }
break; break;
@@ -293,15 +309,6 @@ public class UpdaterController {
return true; return true;
} }
public void setUpdatesNotAvailableOnline(List<String> downloadIds) {
for (String downloadId : downloadIds) {
DownloadEntry update = mDownloads.get(downloadId);
if (update != null) {
update.mUpdate.setAvailableOnline(false);
}
}
}
public void setUpdatesAvailableOnline(List<String> downloadIds, boolean purgeList) { public void setUpdatesAvailableOnline(List<String> downloadIds, boolean purgeList) {
List<String> toRemove = new ArrayList<>(); List<String> toRemove = new ArrayList<>();
for (DownloadEntry entry : mDownloads.values()) { for (DownloadEntry entry : mDownloads.values()) {
@@ -327,9 +334,12 @@ public class UpdaterController {
Log.d(TAG, "Adding download: " + updateInfo.getDownloadId()); Log.d(TAG, "Adding download: " + updateInfo.getDownloadId());
if (mDownloads.containsKey(updateInfo.getDownloadId())) { if (mDownloads.containsKey(updateInfo.getDownloadId())) {
Log.d(TAG, "Download (" + updateInfo.getDownloadId() + ") already added"); Log.d(TAG, "Download (" + updateInfo.getDownloadId() + ") already added");
Update updateAdded = mDownloads.get(updateInfo.getDownloadId()).mUpdate; DownloadEntry entry = mDownloads.get(updateInfo.getDownloadId());
updateAdded.setAvailableOnline(availableOnline && updateAdded.getAvailableOnline()); if (entry != null) {
updateAdded.setDownloadUrl(updateInfo.getDownloadUrl()); Update updateAdded = entry.mUpdate;
updateAdded.setAvailableOnline(availableOnline && updateAdded.getAvailableOnline());
updateAdded.setDownloadUrl(updateInfo.getDownloadUrl());
}
return false; return false;
} }
Update update = new Update(updateInfo); Update update = new Update(updateInfo);
@@ -344,12 +354,18 @@ public class UpdaterController {
return true; return true;
} }
public boolean startDownload(String downloadId) { @SuppressLint("WakelockTimeout")
public void startDownload(String downloadId) {
Log.d(TAG, "Starting " + downloadId); Log.d(TAG, "Starting " + downloadId);
if (!mDownloads.containsKey(downloadId) || isDownloading(downloadId)) { if (!mDownloads.containsKey(downloadId) || isDownloading(downloadId)) {
return false; return;
} }
Update update = mDownloads.get(downloadId).mUpdate; DownloadEntry entry = mDownloads.get(downloadId);
if (entry == null) {
Log.e(TAG, "Could not get download entry");
return;
}
Update update = entry.mUpdate;
File destination = new File(mDownloadRoot, update.getName()); File destination = new File(mDownloadRoot, update.getName());
if (destination.exists()) { if (destination.exists()) {
destination = Utils.appendSequentialNumber(destination); destination = Utils.appendSequentialNumber(destination);
@@ -369,28 +385,33 @@ public class UpdaterController {
Log.e(TAG, "Could not build download client"); Log.e(TAG, "Could not build download client");
update.setStatus(UpdateStatus.PAUSED_ERROR); update.setStatus(UpdateStatus.PAUSED_ERROR);
notifyUpdateChange(downloadId); notifyUpdateChange(downloadId);
return false; return;
} }
addDownloadClient(mDownloads.get(downloadId), downloadClient); addDownloadClient(entry, downloadClient);
update.setStatus(UpdateStatus.STARTING); update.setStatus(UpdateStatus.STARTING);
notifyUpdateChange(downloadId); notifyUpdateChange(downloadId);
downloadClient.start(); downloadClient.start();
mWakeLock.acquire(); mWakeLock.acquire();
return true;
} }
public boolean resumeDownload(String downloadId) { @SuppressLint("WakelockTimeout")
public void resumeDownload(String downloadId) {
Log.d(TAG, "Resuming " + downloadId); Log.d(TAG, "Resuming " + downloadId);
if (!mDownloads.containsKey(downloadId) || isDownloading(downloadId)) { if (!mDownloads.containsKey(downloadId) || isDownloading(downloadId)) {
return false; return;
} }
Update update = mDownloads.get(downloadId).mUpdate; DownloadEntry entry = mDownloads.get(downloadId);
if (entry == null) {
Log.e(TAG, "Could not get download entry");
return;
}
Update update = entry.mUpdate;
File file = update.getFile(); File file = update.getFile();
if (file == null || !file.exists()) { if (file == null || !file.exists()) {
Log.e(TAG, "The destination file of " + downloadId + " doesn't exist, can't resume"); Log.e(TAG, "The destination file of " + downloadId + " doesn't exist, can't resume");
update.setStatus(UpdateStatus.PAUSED_ERROR); update.setStatus(UpdateStatus.PAUSED_ERROR);
notifyUpdateChange(downloadId); notifyUpdateChange(downloadId);
return false; return;
} }
if (file.exists() && update.getFileSize() > 0 && file.length() >= update.getFileSize()) { if (file.exists() && update.getFileSize() > 0 && file.length() >= update.getFileSize()) {
Log.d(TAG, "File already downloaded, starting verification"); Log.d(TAG, "File already downloaded, starting verification");
@@ -411,31 +432,31 @@ public class UpdaterController {
Log.e(TAG, "Could not build download client"); Log.e(TAG, "Could not build download client");
update.setStatus(UpdateStatus.PAUSED_ERROR); update.setStatus(UpdateStatus.PAUSED_ERROR);
notifyUpdateChange(downloadId); notifyUpdateChange(downloadId);
return false; return;
} }
addDownloadClient(mDownloads.get(downloadId), downloadClient); addDownloadClient(entry, downloadClient);
update.setStatus(UpdateStatus.STARTING); update.setStatus(UpdateStatus.STARTING);
notifyUpdateChange(downloadId); notifyUpdateChange(downloadId);
downloadClient.resume(); downloadClient.resume();
mWakeLock.acquire(); mWakeLock.acquire();
} }
return true;
} }
public boolean pauseDownload(String downloadId) { public void pauseDownload(String downloadId) {
Log.d(TAG, "Pausing " + downloadId); Log.d(TAG, "Pausing " + downloadId);
if (!isDownloading(downloadId)) { if (!isDownloading(downloadId)) {
return false; return;
} }
DownloadEntry entry = mDownloads.get(downloadId); DownloadEntry entry = mDownloads.get(downloadId);
entry.mDownloadClient.cancel(); if (entry != null) {
removeDownloadClient(entry); entry.mDownloadClient.cancel();
entry.mUpdate.setStatus(UpdateStatus.PAUSED); removeDownloadClient(entry);
entry.mUpdate.setEta(0); entry.mUpdate.setStatus(UpdateStatus.PAUSED);
entry.mUpdate.setSpeed(0); entry.mUpdate.setEta(0);
notifyUpdateChange(downloadId); entry.mUpdate.setSpeed(0);
return true; notifyUpdateChange(downloadId);
}
} }
private void deleteUpdateAsync(final Update update) { private void deleteUpdateAsync(final Update update) {
@@ -448,30 +469,27 @@ public class UpdaterController {
}).start(); }).start();
} }
public boolean deleteUpdate(String downloadId) { public void deleteUpdate(String downloadId) {
Log.d(TAG, "Cancelling " + downloadId); Log.d(TAG, "Cancelling " + downloadId);
if (!mDownloads.containsKey(downloadId) || isDownloading(downloadId)) { if (!mDownloads.containsKey(downloadId) || isDownloading(downloadId)) {
return false; return;
} }
Update update = mDownloads.get(downloadId).mUpdate; DownloadEntry entry = mDownloads.get(downloadId);
update.setStatus(UpdateStatus.DELETED); if (entry != null) {
update.setProgress(0); Update update = entry.mUpdate;
update.setPersistentStatus(UpdateStatus.Persistent.UNKNOWN); update.setStatus(UpdateStatus.DELETED);
deleteUpdateAsync(update); update.setProgress(0);
update.setPersistentStatus(UpdateStatus.Persistent.UNKNOWN);
deleteUpdateAsync(update);
if (!update.getAvailableOnline()) { if (!update.getAvailableOnline()) {
Log.d(TAG, "Download no longer available online, removing"); Log.d(TAG, "Download no longer available online, removing");
mDownloads.remove(downloadId); mDownloads.remove(downloadId);
notifyUpdateDelete(downloadId); notifyUpdateDelete(downloadId);
} else { } else {
notifyUpdateChange(downloadId); notifyUpdateChange(downloadId);
}
} }
return true;
}
public Set<String> getIds() {
return mDownloads.keySet();
} }
public List<UpdateInfo> getUpdates() { public List<UpdateInfo> getUpdates() {
@@ -493,6 +511,7 @@ public class UpdaterController {
} }
public boolean isDownloading(String downloadId) { public boolean isDownloading(String downloadId) {
//noinspection ConstantConditions
return mDownloads.containsKey(downloadId) && return mDownloads.containsKey(downloadId) &&
mDownloads.get(downloadId).mDownloadClient != null; mDownloads.get(downloadId).mDownloadClient != null;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -85,7 +85,7 @@ public class UpdaterService extends Service {
mUpdaterController = UpdaterController.getInstance(this); mUpdaterController = UpdaterController.getInstance(this);
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNotificationManager = getSystemService(NotificationManager.class);
NotificationChannel notificationChannel = new NotificationChannel( NotificationChannel notificationChannel = new NotificationChannel(
ONGOING_NOTIFICATION_CHANNEL, ONGOING_NOTIFICATION_CHANNEL,
getString(R.string.ongoing_channel_title), getString(R.string.ongoing_channel_title),
@@ -123,8 +123,7 @@ public class UpdaterService extends Service {
handleInstallProgress(update); handleInstallProgress(update);
} else if (UpdaterController.ACTION_UPDATE_REMOVED.equals(intent.getAction())) { } else if (UpdaterController.ACTION_UPDATE_REMOVED.equals(intent.getAction())) {
Bundle extras = mNotificationBuilder.getExtras(); Bundle extras = mNotificationBuilder.getExtras();
if (extras != null && downloadId.equals( if (downloadId.equals(extras.getString(UpdaterController.EXTRA_DOWNLOAD_ID))) {
extras.getString(UpdaterController.EXTRA_DOWNLOAD_ID))) {
mNotificationBuilder.setExtras(null); mNotificationBuilder.setExtras(null);
UpdateInfo update = mUpdaterController.getUpdate(downloadId); UpdateInfo update = mUpdaterController.getUpdate(downloadId);
if (update.getStatus() != UpdateStatus.INSTALLED) { if (update.getStatus() != UpdateStatus.INSTALLED) {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,27 +17,23 @@ package org.lineageos.updater.download;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Map;
public interface DownloadClient { public interface DownloadClient {
interface DownloadCallback { interface DownloadCallback {
void onResponse(int statusCode, String url, Headers headers); void onResponse(Headers headers);
void onSuccess(File destination); void onSuccess();
void onFailure(boolean cancelled); void onFailure(boolean cancelled);
} }
interface ProgressListener { interface ProgressListener {
void update(long bytesRead, long contentLength, long speed, long eta, boolean done); void update(long bytesRead, long contentLength, long speed, long eta);
} }
interface Headers { interface Headers {
String get(String name); String get(String name);
Map<String, List<String>> getAll();
} }
/** /**

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -51,10 +51,6 @@ public class HttpURLConnectionClient implements DownloadClient {
return mClient.getHeaderField(name); return mClient.getHeaderField(name);
} }
@Override
public Map<String, List<String>> getAll() {
return mClient.getHeaderFields();
}
} }
HttpURLConnectionClient(String url, File destination, HttpURLConnectionClient(String url, File destination,
@@ -179,8 +175,8 @@ public class HttpURLConnectionClient implements DownloadClient {
String protocol = mClient.getURL().getProtocol(); String protocol = mClient.getURL().getProtocol();
class DuplicateLink { class DuplicateLink {
private String mUrl; private final String mUrl;
private int mPriority; private final int mPriority;
private DuplicateLink(String url, int priority) { private DuplicateLink(String url, int priority) {
mUrl = url; mUrl = url;
mPriority = priority; mPriority = priority;
@@ -233,9 +229,11 @@ public class HttpURLConnectionClient implements DownloadClient {
} catch (IOException e) { } catch (IOException e) {
if (duplicates != null && !duplicates.isEmpty()) { if (duplicates != null && !duplicates.isEmpty()) {
DuplicateLink link = duplicates.poll(); DuplicateLink link = duplicates.poll();
duplicates.remove(link); if (link != null) {
newUrl = link.mUrl; duplicates.remove(link);
Log.e(TAG, "Using duplicate link " + link.mUrl, e); newUrl = link.mUrl;
Log.e(TAG, "Using duplicate link " + link.mUrl, e);
}
} else { } else {
throw e; throw e;
} }
@@ -255,7 +253,7 @@ public class HttpURLConnectionClient implements DownloadClient {
responseCode = mClient.getResponseCode(); responseCode = mClient.getResponseCode();
} }
mCallback.onResponse(responseCode, mClient.getURL().toString(), new Headers()); mCallback.onResponse(new Headers());
if (mResume && isPartialContentCode(responseCode)) { if (mResume && isPartialContentCode(responseCode)) {
mTotalBytesRead = mDestination.length(); mTotalBytesRead = mDestination.length();
@@ -279,12 +277,11 @@ public class HttpURLConnectionClient implements DownloadClient {
calculateSpeed(); calculateSpeed();
calculateEta(); calculateEta();
if (mProgressListener != null) { if (mProgressListener != null) {
mProgressListener.update(mTotalBytesRead, mTotalBytes, mSpeed, mEta, mProgressListener.update(mTotalBytesRead, mTotalBytes, mSpeed, mEta);
false);
} }
} }
if (mProgressListener != null) { if (mProgressListener != null) {
mProgressListener.update(mTotalBytesRead, mTotalBytes, mSpeed, mEta, true); mProgressListener.update(mTotalBytesRead, mTotalBytes, mSpeed, mEta);
} }
outputStream.flush(); outputStream.flush();
@@ -292,7 +289,7 @@ public class HttpURLConnectionClient implements DownloadClient {
if (isInterrupted()) { if (isInterrupted()) {
mCallback.onFailure(true); mCallback.onFailure(true);
} else { } else {
mCallback.onSuccess(mDestination); mCallback.onSuccess();
} }
} }
} catch (IOException e) { } catch (IOException e) {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -34,9 +34,9 @@ public class FileUtils {
} }
private static class CallbackByteChannel implements ReadableByteChannel { private static class CallbackByteChannel implements ReadableByteChannel {
private ProgressCallBack mCallback; private final ProgressCallBack mCallback;
private long mSize; private final long mSize;
private ReadableByteChannel mReadableByteChannel; private final ReadableByteChannel mReadableByteChannel;
private long mSizeRead; private long mSizeRead;
private int mProgress; private int mProgress;
@@ -86,13 +86,10 @@ public class FileUtils {
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Could not copy file", e); Log.e(TAG, "Could not copy file", e);
if (destFile.exists()) { if (destFile.exists()) {
//noinspection ResultOfMethodCallIgnored
destFile.delete(); destFile.delete();
} }
throw e; throw e;
} }
} }
public static void copyFile(File sourceFile, File destFile) throws IOException {
copyFile(sourceFile, destFile, null);
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -36,13 +36,6 @@ public final class StringGenerator {
return f.format(date); return f.format(date);
} }
public static String getTimeLocalizedUTC(Context context, long unixTimestamp) {
DateFormat f = DateFormat.getTimeInstance(DateFormat.SHORT, getCurrentLocale(context));
f.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = new Date(unixTimestamp * 1000);
return f.format(date);
}
public static String getDateLocalized(Context context, int dateFormat, long unixTimestamp) { public static String getDateLocalized(Context context, int dateFormat, long unixTimestamp) {
DateFormat f = DateFormat.getDateInstance(dateFormat, getCurrentLocale(context)); DateFormat f = DateFormat.getDateInstance(dateFormat, getCurrentLocale(context));
Date date = new Date(unixTimestamp * 1000); Date date = new Date(unixTimestamp * 1000);
@@ -56,13 +49,6 @@ public final class StringGenerator {
return f.format(date); return f.format(date);
} }
public static String getDateTimeLocalized(Context context, long unixTimestamp) {
DateFormat f = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT,
getCurrentLocale(context));
Date date = new Date(unixTimestamp * 1000);
return f.format(date);
}
public static String bytesToMegabytes(Context context, long bytes) { public static String bytesToMegabytes(Context context, long bytes) {
return String.format(getCurrentLocale(context), "%.0f", bytes / 1024.f / 1024.f); return String.format(getCurrentLocale(context), "%.0f", bytes / 1024.f / 1024.f);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017-2021 The LineageOS Project * Copyright (C) 2017-2022 The LineageOS Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Environment;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@@ -122,14 +121,14 @@ public class Utils {
throws IOException, JSONException { throws IOException, JSONException {
List<UpdateInfo> updates = new ArrayList<>(); List<UpdateInfo> updates = new ArrayList<>();
String json = ""; StringBuilder json = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(file))) { try (BufferedReader br = new BufferedReader(new FileReader(file))) {
for (String line; (line = br.readLine()) != null;) { for (String line; (line = br.readLine()) != null;) {
json += line; json.append(line);
} }
} }
JSONObject obj = new JSONObject(json); JSONObject obj = new JSONObject(json.toString());
JSONArray updatesList = obj.getJSONArray("response"); JSONArray updatesList = obj.getJSONArray("response");
for (int i = 0; i < updatesList.length(); i++) { for (int i = 0; i < updatesList.length(); i++) {
if (updatesList.isNull(i)) { if (updatesList.isNull(i)) {
@@ -186,15 +185,13 @@ public class Utils {
} }
public static boolean isNetworkAvailable(Context context) { public static boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService( ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo(); NetworkInfo info = cm.getActiveNetworkInfo();
return !(info == null || !info.isConnected() || !info.isAvailable()); return !(info == null || !info.isConnected() || !info.isAvailable());
} }
public static boolean isOnWifiOrEthernet(Context context) { public static boolean isOnWifiOrEthernet(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService( ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo(); NetworkInfo info = cm.getActiveNetworkInfo();
return (info != null && (info.getType() == ConnectivityManager.TYPE_ETHERNET return (info != null && (info.getType() == ConnectivityManager.TYPE_ETHERNET
|| info.getType() == ConnectivityManager.TYPE_WIFI)); || info.getType() == ConnectivityManager.TYPE_WIFI));
@@ -206,8 +203,6 @@ public class Utils {
* @param oldJson old update list * @param oldJson old update list
* @param newJson new update list * @param newJson new update list
* @return true if newJson has at least a compatible update not available in oldJson * @return true if newJson has at least a compatible update not available in oldJson
* @throws IOException
* @throws JSONException
*/ */
public static boolean checkForNewUpdates(File oldJson, File newJson) public static boolean checkForNewUpdates(File oldJson, File newJson)
throws IOException, JSONException { throws IOException, JSONException {
@@ -264,6 +259,7 @@ public class Utils {
return; return;
} }
for (File file : uncryptFiles) { for (File file : uncryptFiles) {
//noinspection ResultOfMethodCallIgnored
file.delete(); file.delete();
} }
} }
@@ -273,7 +269,6 @@ public class Utils {
* the user can't access and that might have stale files. This can happen if * the user can't access and that might have stale files. This can happen if
* the data of the application are wiped. * the data of the application are wiped.
* *
* @param context
*/ */
public static void cleanupDownloadsDir(Context context) { public static void cleanupDownloadsDir(Context context) {
File downloadPath = getDownloadPath(context); File downloadPath = getDownloadPath(context);
@@ -290,6 +285,7 @@ public class Utils {
lastUpdatePath != null) { lastUpdatePath != null) {
File lastUpdate = new File(lastUpdatePath); File lastUpdate = new File(lastUpdatePath);
if (lastUpdate.exists()) { if (lastUpdate.exists()) {
//noinspection ResultOfMethodCallIgnored
lastUpdate.delete(); lastUpdate.delete();
// Remove the pref not to delete the file if re-downloaded // Remove the pref not to delete the file if re-downloaded
preferences.edit().remove(Constants.PREF_INSTALL_PACKAGE_PATH).apply(); preferences.edit().remove(Constants.PREF_INSTALL_PACKAGE_PATH).apply();
@@ -319,6 +315,7 @@ public class Utils {
for (File file : files) { for (File file : files) {
if (!knownPaths.contains(file.getAbsolutePath())) { if (!knownPaths.contains(file.getAbsolutePath())) {
Log.d(TAG, "Deleting " + file.getAbsolutePath()); Log.d(TAG, "Deleting " + file.getAbsolutePath());
//noinspection ResultOfMethodCallIgnored
file.delete(); file.delete();
} }
} }
@@ -367,7 +364,8 @@ public class Utils {
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN); return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
} }
public static void addToClipboard(Context context, String label, String text, String toastMessage) { public static void addToClipboard(Context context, String label, String text,
String toastMessage) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService( ClipboardManager clipboard = (ClipboardManager) context.getSystemService(
Context.CLIPBOARD_SERVICE); Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(label, text); ClipData clip = ClipData.newPlainText(label, text);

View File

@@ -32,10 +32,6 @@ public class Update extends UpdateBase implements UpdateInfo {
public Update() { public Update() {
} }
public Update(UpdateBaseInfo update) {
super(update);
}
public Update(UpdateInfo update) { public Update(UpdateInfo update) {
super(update); super(update);
mStatus = update.getStatus(); mStatus = update.getStatus();

View File

@@ -19,7 +19,6 @@ public enum UpdateStatus {
UNKNOWN, UNKNOWN,
STARTING, STARTING,
DOWNLOADING, DOWNLOADING,
DOWNLOADED,
PAUSED, PAUSED,
PAUSED_ERROR, PAUSED_ERROR,
DELETED, DELETED,

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@@ -21,8 +22,9 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
} }
@Override @Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout,
View target, float velocityX, float velocityY, boolean consumed) { @NonNull AppBarLayout child, @NonNull View target,
float velocityX, float velocityY, boolean consumed) {
if (velocityY > 0 && !isPositive || velocityY < 0 && isPositive) { if (velocityY > 0 && !isPositive || velocityY < 0 && isPositive) {
velocityY = velocityY * -1; velocityY = velocityY * -1;
} }
@@ -37,9 +39,10 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
} }
@Override @Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout,
View target, int dx, int dy, int[] consumed) { @NonNull AppBarLayout child, @NonNull View target,
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); int dx, int dy, @NonNull int[] consumed, int type) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
isPositive = dy > 0; isPositive = dy > 0;
} }
} }