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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/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");
* 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 File mSource;
private File mDestination;
private FileUtils.ProgressCallBack mProgressCallBack;
private Runnable mRunnableComplete;
private Runnable mRunnableFailed;
private final File mSource;
private final File mDestination;
private final FileUtils.ProgressCallBack mProgressCallBack;
private final Runnable mRunnableComplete;
private final Runnable mRunnableFailed;
private ExportRunnable(File source, File destination,
FileUtils.ProgressCallBack progressCallBack,
@@ -131,13 +131,13 @@ public class ExportUpdateService extends Service {
}
private void cleanUp() {
//noinspection ResultOfMethodCallIgnored
mDestination.delete();
}
}
private void startExporting(File source, File destination) {
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
NotificationChannel notificationChannel = new NotificationChannel(
EXPORT_NOTIFICATION_CHANNEL,
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");
* 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))
.setContentText(buildInfo);
NotificationManager nm = (NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
NotificationManager nm = context.getSystemService(NotificationManager.class);
nm.createNotificationChannel(notificationChannel);
nm.notify(0, builder.build());
}
@@ -88,7 +87,7 @@ public class UpdaterReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_INSTALL_REBOOT.equals(intent.getAction())) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager pm = context.getSystemService(PowerManager.class);
pm.reboot(null);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
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");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/
package org.lineageos.updater;
import android.annotation.SuppressLint;
import android.app.UiModeManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -39,14 +40,13 @@ import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager;
@@ -92,10 +92,10 @@ public class UpdatesActivity extends UpdatesListActivity {
super.onCreate(savedInstanceState);
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;
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
mAdapter = new UpdatesListAdapter(this);
recyclerView.setAdapter(mAdapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
@@ -111,7 +111,7 @@ public class UpdatesActivity extends UpdatesListActivity {
if (UpdaterController.ACTION_UPDATE_STATUS.equals(intent.getAction())) {
String downloadId = intent.getStringExtra(UpdaterController.EXTRA_DOWNLOAD_ID);
handleDownloadStatusChange(downloadId);
mAdapter.notifyDataSetChanged();
mAdapter.notifyItemChanged(downloadId);
} else if (UpdaterController.ACTION_DOWNLOAD_PROGRESS.equals(intent.getAction()) ||
UpdaterController.ACTION_INSTALL_PROGRESS.equals(intent.getAction())) {
String downloadId = intent.getStringExtra(UpdaterController.EXTRA_DOWNLOAD_ID);
@@ -124,31 +124,33 @@ public class UpdatesActivity extends UpdatesListActivity {
};
if (!mIsTV) {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ActionBar actionBar = getSupportActionBar();
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,
BuildInfoUtils.getBuildVersion()));
updateLastCheckedString();
TextView headerBuildVersion = (TextView) findViewById(R.id.header_build_version);
TextView headerBuildVersion = findViewById(R.id.header_build_version);
headerBuildVersion.setText(
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,
DateFormat.LONG, BuildInfoUtils.getBuildDateTimestamp()));
if (!mIsTV) {
// Switch between header title and appbar title minimizing overlaps
final CollapsingToolbarLayout collapsingToolbar =
(CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
final AppBarLayout appBar = (AppBarLayout) findViewById(R.id.app_bar);
final CollapsingToolbarLayout collapsingToolbar = findViewById(R.id.collapsing_toolbar);
final AppBarLayout appBar = findViewById(R.id.app_bar);
appBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
boolean mIsShown = false;
@@ -175,18 +177,8 @@ public class UpdatesActivity extends UpdatesListActivity {
appBar.setExpanded(false);
}
} else {
findViewById(R.id.refresh).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downloadUpdatesList(true);
}
});
findViewById(R.id.preferences).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showPreferencesDialog();
}
});
findViewById(R.id.refresh).setOnClickListener(v -> downloadUpdatesList(true));
findViewById(R.id.preferences).setOnClickListener(v -> showPreferencesDialog());
}
}
@@ -222,22 +214,19 @@ public class UpdatesActivity extends UpdatesListActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_refresh: {
int itemId = item.getItemId();
if (itemId == R.id.menu_refresh) {
downloadUpdatesList(true);
return true;
}
case R.id.menu_preferences: {
} else if (itemId == R.id.menu_preferences) {
showPreferencesDialog();
return true;
}
case R.id.menu_show_changelog: {
} else if (itemId == R.id.menu_show_changelog) {
Intent openUrl = new Intent(Intent.ACTION_VIEW,
Uri.parse(Utils.getChangelogURL(this)));
startActivity(openUrl);
return true;
}
}
return super.onOptionsItemSelected(item);
}
@@ -247,7 +236,7 @@ public class UpdatesActivity extends UpdatesListActivity {
return true;
}
private ServiceConnection mConnection = new ServiceConnection() {
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
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
UpdatesCheckReceiver.cancelUpdatesCheck(this);
//noinspection ResultOfMethodCallIgnored
jsonNew.renameTo(json);
} catch (IOException | JSONException e) {
Log.e(TAG, "Could not read json", e);
@@ -356,12 +346,11 @@ public class UpdatesActivity extends UpdatesListActivity {
}
@Override
public void onResponse(int statusCode, String url,
DownloadClient.Headers headers) {
public void onResponse(DownloadClient.Headers headers) {
}
@Override
public void onSuccess(File destination) {
public void onSuccess() {
runOnUiThread(() -> {
Log.d(TAG, "List downloaded");
processNewJson(jsonFile, jsonFileTmp, manualRefresh);
@@ -394,7 +383,7 @@ public class UpdatesActivity extends UpdatesListActivity {
String lastCheckString = getString(R.string.header_last_updates_check,
StringGenerator.getDateLocalized(this, DateFormat.LONG, 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);
}
@@ -451,14 +440,14 @@ public class UpdatesActivity extends UpdatesListActivity {
}
}
@SuppressLint("ClickableViewAccessibility")
private void showPreferencesDialog() {
View view = LayoutInflater.from(this).inflate(R.layout.preferences_dialog, null);
Spinner autoCheckInterval =
view.findViewById(R.id.preferences_auto_updates_check_interval);
Switch autoDelete = view.findViewById(R.id.preferences_auto_delete_updates);
Switch dataWarning = view.findViewById(R.id.preferences_mobile_data_warning);
Switch abPerfMode = view.findViewById(R.id.preferences_ab_perf_mode);
Switch updateRecovery = view.findViewById(R.id.preferences_update_recovery);
Spinner autoCheckInterval = view.findViewById(R.id.preferences_auto_updates_check_interval);
SwitchCompat autoDelete = view.findViewById(R.id.preferences_auto_delete_updates);
SwitchCompat dataWarning = view.findViewById(R.id.preferences_mobile_data_warning);
SwitchCompat abPerfMode = view.findViewById(R.id.preferences_ab_perf_mode);
SwitchCompat updateRecovery = view.findViewById(R.id.preferences_update_recovery);
if (!Utils.isABDevice()) {
abPerfMode.setVisibility(View.GONE);
@@ -471,7 +460,7 @@ public class UpdatesActivity extends UpdatesListActivity {
abPerfMode.setChecked(prefs.getBoolean(Constants.PREF_AB_PERF_MODE, false));
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.
updateRecovery.setVisibility(View.GONE);
} else if (Utils.isRecoveryUpdateExecPresent()) {
@@ -505,12 +494,9 @@ public class UpdatesActivity extends UpdatesListActivity {
prefs.edit()
.putInt(Constants.PREF_AUTO_UPDATES_CHECK_INTERVAL,
autoCheckInterval.getSelectedItemPosition())
.putBoolean(Constants.PREF_AUTO_DELETE_UPDATES,
autoDelete.isChecked())
.putBoolean(Constants.PREF_MOBILE_DATA_WARNING,
dataWarning.isChecked())
.putBoolean(Constants.PREF_AB_PERF_MODE,
abPerfMode.isChecked())
.putBoolean(Constants.PREF_AUTO_DELETE_UPDATES, autoDelete.isChecked())
.putBoolean(Constants.PREF_MOBILE_DATA_WARNING, dataWarning.isChecked())
.putBoolean(Constants.PREF_AB_PERF_MODE, abPerfMode.isChecked())
.apply();
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");
* you may not use this file except in compliance with the License.
@@ -84,17 +84,17 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
}
@Override
public void onResponse(int statusCode, String url,
DownloadClient.Headers headers) {
public void onResponse(DownloadClient.Headers headers) {
}
@Override
public void onSuccess(File destination) {
public void onSuccess() {
try {
if (json.exists() && Utils.checkForNewUpdates(json, jsonNew)) {
showNotification(context);
updateRepeatingUpdatesCheck(context);
}
//noinspection ResultOfMethodCallIgnored
jsonNew.renameTo(json);
long currentMillis = System.currentTimeMillis();
preferences.edit()
@@ -123,8 +123,8 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
}
private static void showNotification(Context context) {
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationManager notificationManager = context.getSystemService(
NotificationManager.class);
NotificationChannel notificationChannel = new NotificationChannel(
NEW_UPDATES_NOTIFICATION_CHANNEL,
context.getString(R.string.new_updates_channel_title),
@@ -159,7 +159,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
}
PendingIntent updateCheckIntent = getRepeatingUpdatesCheckIntent(context);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
alarmMgr.setRepeating(AlarmManager.RTC, System.currentTimeMillis() +
Utils.getUpdateCheckInterval(context), Utils.getUpdateCheckInterval(context),
updateCheckIntent);
@@ -170,7 +170,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
}
public static void cancelRepeatingUpdatesCheck(Context context) {
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
alarmMgr.cancel(getRepeatingUpdatesCheckIntent(context));
}
@@ -183,7 +183,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
public static void scheduleUpdatesCheck(Context context) {
long millisToNextCheck = AlarmManager.INTERVAL_HOUR * 2;
PendingIntent updateCheckIntent = getUpdatesCheckIntent(context);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + millisToNextCheck,
updateCheckIntent);
@@ -193,7 +193,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver {
}
public static void cancelUpdatesCheck(Context context) {
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
AlarmManager alarmMgr = context.getSystemService(AlarmManager.class);
alarmMgr.cancel(getUpdatesCheckIntent(context));
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");
* 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);
}
public long addUpdate(Update update) {
public void addUpdateWithOnConflict(Update update, int conflictAlgorithm) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
fillContentValues(update, values);
return db.insert(UpdateEntry.TABLE_NAME, null, values);
}
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);
db.insertWithOnConflict(UpdateEntry.TABLE_NAME, null, values, conflictAlgorithm);
}
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());
}
public boolean removeUpdate(String downloadId) {
public void removeUpdate(String downloadId) {
SQLiteDatabase db = getWritableDatabase();
String selection = UpdateEntry.COLUMN_NAME_DOWNLOAD_ID + " = ?";
String[] selectionArgs = {downloadId};
return db.delete(UpdateEntry.TABLE_NAME, selection, selectionArgs) != 0;
db.delete(UpdateEntry.TABLE_NAME, selection, selectionArgs);
}
public boolean removeUpdate(long rowId) {
SQLiteDatabase db = getWritableDatabase();
String selection = UpdateEntry._ID + " = " + rowId;
return db.delete(UpdateEntry.TABLE_NAME, selection, null) != 0;
}
public boolean changeUpdateStatus(Update update) {
public void changeUpdateStatus(Update update) {
String selection = UpdateEntry.COLUMN_NAME_DOWNLOAD_ID + " = ?";
String[] selectionArgs = {update.getDownloadId()};
return changeUpdateStatus(selection, selectionArgs, update.getPersistentStatus());
changeUpdateStatus(selection, selectionArgs, update.getPersistentStatus());
}
public boolean changeUpdateStatus(long rowId, int status) {
String selection = UpdateEntry._ID + " = " + rowId;
return changeUpdateStatus(selection, null, status);
}
private boolean changeUpdateStatus(String selection, String[] selectionArgs,
private void changeUpdateStatus(String selection, String[] selectionArgs,
int status) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(UpdateEntry.COLUMN_NAME_STATUS, status);
return db.update(UpdateEntry.TABLE_NAME, values, selection, selectionArgs) != 0;
}
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;
db.update(UpdateEntry.TABLE_NAME, values, selection, selectionArgs);
}
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");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
*/
package org.lineageos.updater;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
@@ -39,6 +38,7 @@ import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.view.menu.MenuBuilder;
@@ -77,7 +77,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
private List<String> mDownloadIds;
private String mSelectedDownload;
private UpdaterController mUpdaterController;
private UpdatesListActivity mActivity;
private final UpdatesListActivity mActivity;
private AlertDialog infoDialog;
@@ -93,27 +93,27 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private Button mAction;
private ImageButton mMenu;
private final Button mAction;
private final ImageButton mMenu;
private TextView mBuildDate;
private TextView mBuildVersion;
private TextView mBuildSize;
private final TextView mBuildDate;
private final TextView mBuildVersion;
private final TextView mBuildSize;
private ProgressBar mProgressBar;
private TextView mProgressText;
private final ProgressBar mProgressBar;
private final TextView mProgressText;
public ViewHolder(final View view) {
super(view);
mAction = (Button) view.findViewById(R.id.update_action);
mMenu = (ImageButton) view.findViewById(R.id.update_menu);
mAction = view.findViewById(R.id.update_action);
mMenu = view.findViewById(R.id.update_menu);
mBuildDate = (TextView) view.findViewById(R.id.build_date);
mBuildVersion = (TextView) view.findViewById(R.id.build_version);
mBuildSize = (TextView) view.findViewById(R.id.build_size);
mBuildDate = view.findViewById(R.id.build_date);
mBuildVersion = view.findViewById(R.id.build_version);
mBuildSize = view.findViewById(R.id.build_size);
mProgressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
mProgressText = (TextView) view.findViewById(R.id.progress_text);
mProgressBar = view.findViewById(R.id.progress_bar);
mProgressText = view.findViewById(R.id.progress_text);
}
}
@@ -125,6 +125,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
mAlphaDisabledValue = tv.getFloat();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext())
@@ -133,7 +134,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
}
@Override
public void onViewDetachedFromWindow(ViewHolder holder) {
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if (infoDialog != null) {
@@ -191,8 +192,8 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
String total = Formatter.formatShortFileSize(mActivity, update.getFileSize());
String percentage = NumberFormat.getPercentInstance().format(
update.getProgress() / 100.f);
viewHolder.mProgressText.setText(mActivity.getString(R.string.list_download_progress_new,
downloaded, total, percentage));
viewHolder.mProgressText.setText(mActivity.getString(
R.string.list_download_progress_new, downloaded, total, percentage));
viewHolder.mProgressBar.setIndeterminate(false);
viewHolder.mProgressBar.setProgress(update.getProgress());
}
@@ -229,7 +230,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
}
@Override
public void onBindViewHolder(final ViewHolder viewHolder, int i) {
public void onBindViewHolder(@NonNull final ViewHolder viewHolder, int i) {
if (mDownloadIds == null) {
viewHolder.mAction.setEnabled(false);
return;
@@ -311,7 +312,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
}
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);
new AlertDialog.Builder(mActivity)
@@ -370,7 +371,10 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
final boolean canInstall = Utils.canInstall(update);
clickListener = enabled ? view -> {
if (canInstall) {
getInstallDialog(downloadId).show();
AlertDialog.Builder installDialog = getInstallDialog(downloadId);
if (installDialog != null) {
installDialog.show();
}
} else {
mActivity.showSnackbar(R.string.snack_update_not_installable,
Snackbar.LENGTH_LONG);
@@ -400,8 +404,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
button.setText(R.string.reboot);
button.setEnabled(enabled);
clickListener = enabled ? view -> {
PowerManager pm =
(PowerManager) mActivity.getSystemService(Context.POWER_SERVICE);
PowerManager pm = mActivity.getSystemService(PowerManager.class);
pm.reboot(null);
} : null;
}
@@ -438,9 +441,7 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
private View.OnClickListener getClickListener(final UpdateInfo update,
final boolean canDelete, View anchor) {
return view -> {
startActionMode(update, canDelete, anchor);
};
return view -> startActionMode(update, canDelete, anchor);
}
private AlertDialog.Builder getInstallDialog(final String downloadId) {
@@ -509,17 +510,17 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
update.getPersistentStatus() == UpdateStatus.Persistent.VERIFIED);
popupMenu.setOnMenuItemClickListener(item -> {
switch (item.getItemId()) {
case R.id.menu_delete_action:
int itemId = item.getItemId();
if (itemId == R.id.menu_delete_action) {
getDeleteDialog(update.getDownloadId()).show();
return true;
case R.id.menu_copy_url:
} else if (itemId == R.id.menu_copy_url) {
Utils.addToClipboard(mActivity,
mActivity.getString(R.string.label_download_url),
update.getDownloadUrl(),
mActivity.getString(R.string.toast_download_url_copied));
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
boolean hasPermission = PermissionsUtils.checkAndRequestStoragePermission(
mActivity, 0);
@@ -561,9 +562,11 @@ public class UpdatesListAdapter extends RecyclerView.Adapter<UpdatesListAdapter.
.setPositiveButton(android.R.string.ok, null)
.setMessage(message)
.show();
TextView textView = (TextView) infoDialog.findViewById(android.R.id.message);
TextView textView = infoDialog.findViewById(android.R.id.message);
if (textView != null) {
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
}
private boolean isBatteryLevelOk() {
Intent intent = mActivity.registerReceiver(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");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ class ABUpdateInstaller {
private final Context mContext;
private String mDownloadId;
private UpdateEngine mUpdateEngine;
private final UpdateEngine mUpdateEngine;
private boolean mBound;
private boolean mFinalizing;
@@ -130,11 +130,6 @@ class ABUpdateInstaller {
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) {
String waitingId = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.PREF_NEEDS_REBOOT_ID, null);
@@ -155,10 +150,10 @@ class ABUpdateInstaller {
return sInstance;
}
public boolean install(String downloadId) {
public void install(String downloadId) {
if (isInstallingUpdate(mContext)) {
Log.e(TAG, "Already installing an update");
return false;
return;
}
mDownloadId = downloadId;
@@ -169,7 +164,7 @@ class ABUpdateInstaller {
mUpdaterController.getActualUpdate(downloadId)
.setStatus(UpdateStatus.INSTALLATION_FAILED);
mUpdaterController.notifyUpdateChange(downloadId);
return false;
return;
}
long offset;
@@ -194,7 +189,7 @@ class ABUpdateInstaller {
mUpdaterController.getActualUpdate(mDownloadId)
.setStatus(UpdateStatus.INSTALLATION_FAILED);
mUpdaterController.notifyUpdateChange(mDownloadId);
return false;
return;
}
if (!mBound) {
@@ -204,7 +199,7 @@ class ABUpdateInstaller {
mUpdaterController.getActualUpdate(downloadId)
.setStatus(UpdateStatus.INSTALLATION_FAILED);
mUpdaterController.notifyUpdateChange(downloadId);
return false;
return;
}
}
@@ -222,17 +217,16 @@ class ABUpdateInstaller {
.putString(PREF_INSTALLING_AB_ID, mDownloadId)
.apply();
return true;
}
public boolean reconnect() {
public void reconnect() {
if (!isInstallingUpdate(mContext)) {
Log.e(TAG, "reconnect: Not installing any update");
return false;
return;
}
if (mBound) {
return true;
return;
}
mDownloadId = PreferenceManager.getDefaultSharedPreferences(mContext)
@@ -242,10 +236,8 @@ class ABUpdateInstaller {
mBound = mUpdateEngine.bind(mUpdateEngineCallback);
if (!mBound) {
Log.e(TAG, "Could not bind");
return false;
}
return true;
}
private void installationDone(boolean needsReboot) {
@@ -257,15 +249,15 @@ class ABUpdateInstaller {
.apply();
}
public boolean cancel() {
public void cancel() {
if (!isInstallingUpdate(mContext)) {
Log.e(TAG, "cancel: Not installing any update");
return false;
return;
}
if (!mBound) {
Log.e(TAG, "Not connected to update engine");
return false;
return;
}
mUpdateEngine.cancel();
@@ -275,22 +267,21 @@ class ABUpdateInstaller {
.setStatus(UpdateStatus.INSTALLATION_CANCELLED);
mUpdaterController.notifyUpdateChange(mDownloadId);
return true;
}
public void setPerformanceMode(boolean enable) {
mUpdateEngine.setPerformanceMode(enable);
}
public boolean suspend() {
public void suspend() {
if (!isInstallingUpdate(mContext)) {
Log.e(TAG, "cancel: Not installing any update");
return false;
return;
}
if (!mBound) {
Log.e(TAG, "Not connected to update engine");
return false;
return;
}
mUpdateEngine.suspend();
@@ -303,18 +294,17 @@ class ABUpdateInstaller {
.putString(PREF_INSTALLING_SUSPENDED_AB_ID, mDownloadId)
.apply();
return true;
}
public boolean resume() {
public void resume() {
if (!isInstallingUpdateSuspended(mContext)) {
Log.e(TAG, "cancel: No update is suspended");
return false;
return;
}
if (!mBound) {
Log.e(TAG, "Not connected to update engine");
return false;
return;
}
mUpdateEngine.resume();
@@ -329,6 +319,5 @@ class ABUpdateInstaller {
.remove(PREF_INSTALLING_SUSPENDED_AB_ID)
.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");
* you may not use this file except in compliance with the License.
@@ -113,7 +113,7 @@ class UpdateInstaller {
Runnable copyUpdateRunnable = new Runnable() {
private long mLastUpdate = -1;
FileUtils.ProgressCallBack mProgressCallBack = new FileUtils.ProgressCallBack() {
final FileUtils.ProgressCallBack mProgressCallBack = new FileUtils.ProgressCallBack() {
@Override
public void update(int progress) {
long now = SystemClock.elapsedRealtime();
@@ -137,12 +137,14 @@ class UpdateInstaller {
.setStatus(UpdateStatus.INSTALLATION_CANCELLED);
mUpdaterController.getActualUpdate(update.getDownloadId())
.setInstallProgress(0);
//noinspection ResultOfMethodCallIgnored
uncryptFile.delete();
} else {
installPackage(uncryptFile, update.getDownloadId());
}
} catch (IOException e) {
Log.e(TAG, "Could not copy update", e);
//noinspection ResultOfMethodCallIgnored
uncryptFile.delete();
mUpdaterController.getActualUpdate(update.getDownloadId())
.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");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/
package org.lineageos.updater.controller;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
@@ -63,11 +64,7 @@ public class UpdaterController {
private final File mDownloadRoot;
private int mActiveDownloads = 0;
private Set<String> mVerifyingUpdates = new HashSet<>();
public static synchronized UpdaterController getInstance() {
return sUpdaterController;
}
private final Set<String> mVerifyingUpdates = new HashSet<>();
protected static synchronized UpdaterController getInstance(Context context) {
if (sUpdaterController == null) {
@@ -80,8 +77,8 @@ public class UpdaterController {
mBroadcastManager = LocalBroadcastManager.getInstance(context);
mUpdatesDbHelper = new UpdatesDbHelper(context);
mDownloadRoot = Utils.getDownloadPath(context);
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Updater");
PowerManager powerManager = context.getSystemService(PowerManager.class);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Updater:wakelock");
mWakeLock.setReferenceCounted(false);
mContext = context.getApplicationContext();
@@ -92,7 +89,7 @@ public class UpdaterController {
}
}
private class DownloadEntry {
private static class DownloadEntry {
final Update mUpdate;
DownloadClient mDownloadClient;
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) {
Intent intent = new Intent();
@@ -156,8 +153,12 @@ public class UpdaterController {
return new DownloadClient.DownloadCallback() {
@Override
public void onResponse(int statusCode, String url, DownloadClient.Headers headers) {
final Update update = mDownloads.get(downloadId).mUpdate;
public void onResponse(DownloadClient.Headers headers) {
final DownloadEntry entry = mDownloads.get(downloadId);
if (entry == null) {
return;
}
final Update update = entry.mUpdate;
String contentLength = headers.get("Content-Length");
if (contentLength != null) {
try {
@@ -177,28 +178,34 @@ public class UpdaterController {
}
@Override
public void onSuccess(File destination) {
public void onSuccess() {
Log.d(TAG, "Download complete");
Update update = mDownloads.get(downloadId).mUpdate;
DownloadEntry entry = mDownloads.get(downloadId);
if (entry != null) {
Update update = entry.mUpdate;
update.setStatus(UpdateStatus.VERIFYING);
removeDownloadClient(mDownloads.get(downloadId));
removeDownloadClient(entry);
verifyUpdateAsync(downloadId);
notifyUpdateChange(downloadId);
tryReleaseWakelock();
}
}
@Override
public void onFailure(boolean cancelled) {
Update update = mDownloads.get(downloadId).mUpdate;
if (cancelled) {
Log.d(TAG, "Download cancelled");
// Already notified
} else {
DownloadEntry entry = mDownloads.get(downloadId);
if (entry != null) {
Update update = entry.mUpdate;
Log.e(TAG, "Download failed");
removeDownloadClient(mDownloads.get(downloadId));
removeDownloadClient(entry);
update.setStatus(UpdateStatus.PAUSED_ERROR);
notifyUpdateChange(downloadId);
}
}
tryReleaseWakelock();
}
};
@@ -210,9 +217,12 @@ public class UpdaterController {
private int mProgress = 0;
@Override
public void update(long bytesRead, long contentLength, long speed, long eta,
boolean done) {
Update update = mDownloads.get(downloadId).mUpdate;
public void update(long bytesRead, long contentLength, long speed, long eta) {
DownloadEntry entry = mDownloads.get(downloadId);
if (entry == null) {
return;
}
Update update = entry.mUpdate;
if (contentLength <= 0) {
if (update.getFileSize() <= 0) {
return;
@@ -224,7 +234,7 @@ public class UpdaterController {
return;
}
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) {
mProgress = progress;
mLastUpdate = now;
@@ -237,12 +247,16 @@ public class UpdaterController {
};
}
@SuppressLint("SetWorldReadable")
private void verifyUpdateAsync(final String downloadId) {
mVerifyingUpdates.add(downloadId);
new Thread(() -> {
Update update = mDownloads.get(downloadId).mUpdate;
DownloadEntry entry = mDownloads.get(downloadId);
if (entry != null) {
Update update = entry.mUpdate;
File file = update.getFile();
if (file.exists() && verifyPackage(file)) {
//noinspection ResultOfMethodCallIgnored
file.setReadable(true, false);
update.setPersistentStatus(UpdateStatus.Persistent.VERIFIED);
mUpdatesDbHelper.changeUpdateStatus(update);
@@ -255,6 +269,7 @@ public class UpdaterController {
}
mVerifyingUpdates.remove(downloadId);
notifyUpdateChange(downloadId);
}
}).start();
}
@@ -266,6 +281,7 @@ public class UpdaterController {
} catch (Exception e) {
Log.e(TAG, "Verification failed", e);
if (file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.delete();
} else {
// The download was probably stopped. Exit silently
@@ -285,7 +301,7 @@ public class UpdaterController {
} else if (update.getFileSize() > 0) {
update.setStatus(UpdateStatus.PAUSED);
int progress = Math.round(
update.getFile().length() * 100 / update.getFileSize());
update.getFile().length() * 100f / update.getFileSize());
update.setProgress(progress);
}
break;
@@ -293,15 +309,6 @@ public class UpdaterController {
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) {
List<String> toRemove = new ArrayList<>();
for (DownloadEntry entry : mDownloads.values()) {
@@ -327,9 +334,12 @@ public class UpdaterController {
Log.d(TAG, "Adding download: " + updateInfo.getDownloadId());
if (mDownloads.containsKey(updateInfo.getDownloadId())) {
Log.d(TAG, "Download (" + updateInfo.getDownloadId() + ") already added");
Update updateAdded = mDownloads.get(updateInfo.getDownloadId()).mUpdate;
DownloadEntry entry = mDownloads.get(updateInfo.getDownloadId());
if (entry != null) {
Update updateAdded = entry.mUpdate;
updateAdded.setAvailableOnline(availableOnline && updateAdded.getAvailableOnline());
updateAdded.setDownloadUrl(updateInfo.getDownloadUrl());
}
return false;
}
Update update = new Update(updateInfo);
@@ -344,12 +354,18 @@ public class UpdaterController {
return true;
}
public boolean startDownload(String downloadId) {
@SuppressLint("WakelockTimeout")
public void startDownload(String downloadId) {
Log.d(TAG, "Starting " + 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());
if (destination.exists()) {
destination = Utils.appendSequentialNumber(destination);
@@ -369,28 +385,33 @@ public class UpdaterController {
Log.e(TAG, "Could not build download client");
update.setStatus(UpdateStatus.PAUSED_ERROR);
notifyUpdateChange(downloadId);
return false;
return;
}
addDownloadClient(mDownloads.get(downloadId), downloadClient);
addDownloadClient(entry, downloadClient);
update.setStatus(UpdateStatus.STARTING);
notifyUpdateChange(downloadId);
downloadClient.start();
mWakeLock.acquire();
return true;
}
public boolean resumeDownload(String downloadId) {
@SuppressLint("WakelockTimeout")
public void resumeDownload(String downloadId) {
Log.d(TAG, "Resuming " + 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();
if (file == null || !file.exists()) {
Log.e(TAG, "The destination file of " + downloadId + " doesn't exist, can't resume");
update.setStatus(UpdateStatus.PAUSED_ERROR);
notifyUpdateChange(downloadId);
return false;
return;
}
if (file.exists() && update.getFileSize() > 0 && file.length() >= update.getFileSize()) {
Log.d(TAG, "File already downloaded, starting verification");
@@ -411,31 +432,31 @@ public class UpdaterController {
Log.e(TAG, "Could not build download client");
update.setStatus(UpdateStatus.PAUSED_ERROR);
notifyUpdateChange(downloadId);
return false;
return;
}
addDownloadClient(mDownloads.get(downloadId), downloadClient);
addDownloadClient(entry, downloadClient);
update.setStatus(UpdateStatus.STARTING);
notifyUpdateChange(downloadId);
downloadClient.resume();
mWakeLock.acquire();
}
return true;
}
public boolean pauseDownload(String downloadId) {
public void pauseDownload(String downloadId) {
Log.d(TAG, "Pausing " + downloadId);
if (!isDownloading(downloadId)) {
return false;
return;
}
DownloadEntry entry = mDownloads.get(downloadId);
if (entry != null) {
entry.mDownloadClient.cancel();
removeDownloadClient(entry);
entry.mUpdate.setStatus(UpdateStatus.PAUSED);
entry.mUpdate.setEta(0);
entry.mUpdate.setSpeed(0);
notifyUpdateChange(downloadId);
return true;
}
}
private void deleteUpdateAsync(final Update update) {
@@ -448,12 +469,14 @@ public class UpdaterController {
}).start();
}
public boolean deleteUpdate(String downloadId) {
public void deleteUpdate(String downloadId) {
Log.d(TAG, "Cancelling " + downloadId);
if (!mDownloads.containsKey(downloadId) || isDownloading(downloadId)) {
return false;
return;
}
Update update = mDownloads.get(downloadId).mUpdate;
DownloadEntry entry = mDownloads.get(downloadId);
if (entry != null) {
Update update = entry.mUpdate;
update.setStatus(UpdateStatus.DELETED);
update.setProgress(0);
update.setPersistentStatus(UpdateStatus.Persistent.UNKNOWN);
@@ -466,12 +489,7 @@ public class UpdaterController {
} else {
notifyUpdateChange(downloadId);
}
return true;
}
public Set<String> getIds() {
return mDownloads.keySet();
}
public List<UpdateInfo> getUpdates() {
@@ -493,6 +511,7 @@ public class UpdaterController {
}
public boolean isDownloading(String downloadId) {
//noinspection ConstantConditions
return mDownloads.containsKey(downloadId) &&
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");
* 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);
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotificationManager = getSystemService(NotificationManager.class);
NotificationChannel notificationChannel = new NotificationChannel(
ONGOING_NOTIFICATION_CHANNEL,
getString(R.string.ongoing_channel_title),
@@ -123,8 +123,7 @@ public class UpdaterService extends Service {
handleInstallProgress(update);
} else if (UpdaterController.ACTION_UPDATE_REMOVED.equals(intent.getAction())) {
Bundle extras = mNotificationBuilder.getExtras();
if (extras != null && downloadId.equals(
extras.getString(UpdaterController.EXTRA_DOWNLOAD_ID))) {
if (downloadId.equals(extras.getString(UpdaterController.EXTRA_DOWNLOAD_ID))) {
mNotificationBuilder.setExtras(null);
UpdateInfo update = mUpdaterController.getUpdate(downloadId);
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");
* 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.IOException;
import java.util.List;
import java.util.Map;
public interface DownloadClient {
interface DownloadCallback {
void onResponse(int statusCode, String url, Headers headers);
void onResponse(Headers headers);
void onSuccess(File destination);
void onSuccess();
void onFailure(boolean cancelled);
}
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 {
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");
* 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);
}
@Override
public Map<String, List<String>> getAll() {
return mClient.getHeaderFields();
}
}
HttpURLConnectionClient(String url, File destination,
@@ -179,8 +175,8 @@ public class HttpURLConnectionClient implements DownloadClient {
String protocol = mClient.getURL().getProtocol();
class DuplicateLink {
private String mUrl;
private int mPriority;
private final String mUrl;
private final int mPriority;
private DuplicateLink(String url, int priority) {
mUrl = url;
mPriority = priority;
@@ -233,9 +229,11 @@ public class HttpURLConnectionClient implements DownloadClient {
} catch (IOException e) {
if (duplicates != null && !duplicates.isEmpty()) {
DuplicateLink link = duplicates.poll();
if (link != null) {
duplicates.remove(link);
newUrl = link.mUrl;
Log.e(TAG, "Using duplicate link " + link.mUrl, e);
}
} else {
throw e;
}
@@ -255,7 +253,7 @@ public class HttpURLConnectionClient implements DownloadClient {
responseCode = mClient.getResponseCode();
}
mCallback.onResponse(responseCode, mClient.getURL().toString(), new Headers());
mCallback.onResponse(new Headers());
if (mResume && isPartialContentCode(responseCode)) {
mTotalBytesRead = mDestination.length();
@@ -279,12 +277,11 @@ public class HttpURLConnectionClient implements DownloadClient {
calculateSpeed();
calculateEta();
if (mProgressListener != null) {
mProgressListener.update(mTotalBytesRead, mTotalBytes, mSpeed, mEta,
false);
mProgressListener.update(mTotalBytesRead, mTotalBytes, mSpeed, mEta);
}
}
if (mProgressListener != null) {
mProgressListener.update(mTotalBytesRead, mTotalBytes, mSpeed, mEta, true);
mProgressListener.update(mTotalBytesRead, mTotalBytes, mSpeed, mEta);
}
outputStream.flush();
@@ -292,7 +289,7 @@ public class HttpURLConnectionClient implements DownloadClient {
if (isInterrupted()) {
mCallback.onFailure(true);
} else {
mCallback.onSuccess(mDestination);
mCallback.onSuccess();
}
}
} 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");
* 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 ProgressCallBack mCallback;
private long mSize;
private ReadableByteChannel mReadableByteChannel;
private final ProgressCallBack mCallback;
private final long mSize;
private final ReadableByteChannel mReadableByteChannel;
private long mSizeRead;
private int mProgress;
@@ -86,13 +86,10 @@ public class FileUtils {
} catch (IOException e) {
Log.e(TAG, "Could not copy file", e);
if (destFile.exists()) {
//noinspection ResultOfMethodCallIgnored
destFile.delete();
}
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");
* you may not use this file except in compliance with the License.
@@ -36,13 +36,6 @@ public final class StringGenerator {
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) {
DateFormat f = DateFormat.getDateInstance(dateFormat, getCurrentLocale(context));
Date date = new Date(unixTimestamp * 1000);
@@ -56,13 +49,6 @@ public final class StringGenerator {
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) {
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");
* 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.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.SystemProperties;
import android.os.storage.StorageManager;
import android.preference.PreferenceManager;
@@ -122,14 +121,14 @@ public class Utils {
throws IOException, JSONException {
List<UpdateInfo> updates = new ArrayList<>();
String json = "";
StringBuilder json = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
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");
for (int i = 0; i < updatesList.length(); i++) {
if (updatesList.isNull(i)) {
@@ -186,15 +185,13 @@ public class Utils {
}
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
NetworkInfo info = cm.getActiveNetworkInfo();
return !(info == null || !info.isConnected() || !info.isAvailable());
}
public static boolean isOnWifiOrEthernet(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
NetworkInfo info = cm.getActiveNetworkInfo();
return (info != null && (info.getType() == ConnectivityManager.TYPE_ETHERNET
|| info.getType() == ConnectivityManager.TYPE_WIFI));
@@ -206,8 +203,6 @@ public class Utils {
* @param oldJson old update list
* @param newJson new update list
* @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)
throws IOException, JSONException {
@@ -264,6 +259,7 @@ public class Utils {
return;
}
for (File file : uncryptFiles) {
//noinspection ResultOfMethodCallIgnored
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 data of the application are wiped.
*
* @param context
*/
public static void cleanupDownloadsDir(Context context) {
File downloadPath = getDownloadPath(context);
@@ -290,6 +285,7 @@ public class Utils {
lastUpdatePath != null) {
File lastUpdate = new File(lastUpdatePath);
if (lastUpdate.exists()) {
//noinspection ResultOfMethodCallIgnored
lastUpdate.delete();
// Remove the pref not to delete the file if re-downloaded
preferences.edit().remove(Constants.PREF_INSTALL_PACKAGE_PATH).apply();
@@ -319,6 +315,7 @@ public class Utils {
for (File file : files) {
if (!knownPaths.contains(file.getAbsolutePath())) {
Log.d(TAG, "Deleting " + file.getAbsolutePath());
//noinspection ResultOfMethodCallIgnored
file.delete();
}
}
@@ -367,7 +364,8 @@ public class Utils {
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(
Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(label, text);

View File

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

View File

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

View File

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