Skip to content

Commit

Permalink
Merge branch 'release/1.9.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Florianisme committed Oct 7, 2023
2 parents 5883266 + b29ea3f commit 608dcef
Show file tree
Hide file tree
Showing 59 changed files with 1,600 additions and 281 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'
- name: Build
run: chmod +x ./gradlew && ./gradlew --parallel --max-workers=8 clean bundleDebug assembleDebug
11 changes: 7 additions & 4 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pipeline {
agent any

tools {
jdk 'Java16'
jdk 'Java17'
}

stages {
Expand All @@ -25,14 +25,17 @@ pipeline {
script {
if (env.BRANCH_NAME == 'master') {
echo 'Publishing Bundle to Beta channel (Not allowed to fail)'
androidApkUpload filesPattern: 'app/build/outputs/bundle/release/app-release.aab,wear/build/outputs/bundle/release/wear-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '20', trackName: 'beta'
androidApkUpload filesPattern: 'app/build/outputs/bundle/release/app-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '20', trackName: 'beta'
androidApkUpload filesPattern: 'wear/build/outputs/bundle/release/wear-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '20', trackName: 'wear:beta'
} else if (env.BRANCH_NAME == 'release') {
echo 'Publishing Bundle to Internal channel (Not allowed to fail)'
androidApkUpload filesPattern: 'app/build/outputs/bundle/release/app-release.aab,wear/build/outputs/bundle/release/wear-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '100', trackName: 'internal'
androidApkUpload filesPattern: 'app/build/outputs/bundle/release/app-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '100', trackName: 'internal'
androidApkUpload filesPattern: 'wear/build/outputs/bundle/release/wear-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '100', trackName: 'wear:internal'
} else if (env.BRANCH_NAME == 'develop' || env.BRANCH_NAME.contains('feature')) {
echo 'Publishing Bundle to Internal channel (Allowed to fail)'
try {
androidApkUpload filesPattern: 'app/build/outputs/bundle/release/app-release.aab,wear/build/outputs/bundle/release/wear-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '100', trackName: 'internal'
androidApkUpload filesPattern: 'app/build/outputs/bundle/release/app-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '100', trackName: 'internal'
androidApkUpload filesPattern: 'wear/build/outputs/bundle/release/wear-release.aab', googleCredentialsId: 'Florianisme', rolloutPercentage: '100', trackName: 'wear:internal'
} catch(error) {
currentBuild.result = 'SUCCESS'
}
Expand Down
22 changes: 15 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apply from: "$rootProject.projectDir/shared-build.gradle"

android {
defaultConfig {
versionCode 71
versionCode 93
wearAppUnbundled true
}
buildFeatures {
Expand All @@ -13,22 +13,30 @@ android {

dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
implementation 'androidx.navigation:navigation-fragment:2.7.3'
implementation 'androidx.navigation:navigation-ui:2.7.3'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'org.reactivestreams:reactive-streams:1.0.3'
implementation 'io.reactivex.rxjava2:rxjava:2.2.9'
implementation 'android.arch.lifecycle:livedata:1.1.1'

implementation "androidx.core:core:1.9.0"
implementation "androidx.core:core:1.12.0"
implementation 'androidx.core:core-google-shortcuts:1.1.0'

def room_version = "2.5.0"
def room_version = "2.5.2"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"

implementation(name: 'android-ping', ext: 'aar')
// SSH
implementation 'com.hierynomus:sshj:0.31.0'
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'

implementation files('libs/android-ping.aar')
implementation project(path: ':shared-models')

// Fix Duplicate class
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import de.florianisme.wakeonlan.persistence.entities.DeviceEntity;

@Database(entities = {DeviceEntity.class}, version = 3, exportSchema = false)
@Database(entities = {DeviceEntity.class}, version = 5, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
public abstract DeviceDao deviceDao();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@

import de.florianisme.wakeonlan.persistence.migrations.MigrationFrom1To2;
import de.florianisme.wakeonlan.persistence.migrations.MigrationFrom2To3;
import de.florianisme.wakeonlan.persistence.migrations.MigrationFrom3To4;
import de.florianisme.wakeonlan.persistence.migrations.MigrationFrom4To5;

public class DatabaseInstanceManager {

private static AppDatabase appDatabase;
private static AppDatabase INSTANCE;

public static synchronized AppDatabase getInstance(Context context) {
if (appDatabase == null) {
appDatabase = Room.databaseBuilder(context, AppDatabase.class, "database-name")
.allowMainThreadQueries()
.addMigrations(new MigrationFrom1To2(), new MigrationFrom2To3())
.build();
public static synchronized AppDatabase getInstance(final Context context) {
if (INSTANCE == null) {
synchronized (AppDatabase.class) {
INSTANCE = Room.databaseBuilder(context, AppDatabase.class, "database-name")
.allowMainThreadQueries()
.addMigrations(new MigrationFrom1To2(), new MigrationFrom2To3(), new MigrationFrom3To4(), new MigrationFrom4To5())
.build();
}
}
return appDatabase;
return INSTANCE;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,40 @@ public class DeviceEntity {
@ColumnInfo(name = "secure_on_password")
public String secureOnPassword;

@ColumnInfo(name = "enable_remote_shutdown", defaultValue = "0")
public boolean enableRemoteShutdown;

@ColumnInfo(name = "ssh_address")
public String sshAddress;

@ColumnInfo(name = "ssh_port")
public Integer sshPort;

@ColumnInfo(name = "ssh_user")
public String sshUsername;

@ColumnInfo(name = "ssh_password")
public String sshPassword;

@ColumnInfo(name = "ssh_command")
public String sshCommand;

@Ignore
public DeviceEntity(int id, String name, String macAddress, String broadcastAddress, int port, String statusIp, String secureOnPassword) {
public DeviceEntity(int id, String name, String macAddress, String broadcastAddress, int port, String statusIp, String secureOnPassword,
boolean enableRemoteShutdown, String sshAddress, Integer sshPort, String sshUsername, String sshPassword, String sshCommand) {
this.id = id;
this.name = name;
this.macAddress = macAddress;
this.broadcastAddress = broadcastAddress;
this.port = port;
this.statusIp = statusIp;
this.secureOnPassword = secureOnPassword;
this.enableRemoteShutdown = enableRemoteShutdown;
this.sshAddress = sshAddress;
this.sshPort = sshPort;
this.sshUsername = sshUsername;
this.sshPassword = sshPassword;
this.sshCommand = sshCommand;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ public Device entityToModel(DeviceEntity entity) {
if (entity == null) {
return new Device();
}
return new Device(entity.id, entity.name, entity.macAddress, entity.broadcastAddress, entity.port, entity.statusIp, entity.secureOnPassword);
return new Device(entity.id, entity.name, entity.macAddress, entity.broadcastAddress, entity.port, entity.statusIp, entity.secureOnPassword,
entity.enableRemoteShutdown, entity.sshAddress, entity.sshPort, entity.sshUsername, entity.sshPassword, entity.sshCommand);
}

@Override
public DeviceEntity modelToEntity(Device model) {
if (model == null) {
return new DeviceEntity();
}
return new DeviceEntity(model.id, model.name, model.macAddress, model.broadcastAddress, model.port, model.statusIp, model.secureOnPassword);
return new DeviceEntity(model.id, model.name, model.macAddress, model.broadcastAddress, model.port, model.statusIp, model.secureOnPassword,
model.remoteShutdownEnabled, model.sshAddress, model.sshPort, model.sshUsername, model.sshPassword, model.sshCommand);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package de.florianisme.wakeonlan.persistence.migrations;

import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;

public class MigrationFrom3To4 extends Migration {

public MigrationFrom3To4() {
super(3, 4);
}

@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE 'Devices' ADD COLUMN 'enable_remote_shutdown' INTEGER DEFAULT 0 NOT NULL"); // Booleans are stored as Integer
database.execSQL("ALTER TABLE 'Devices' ADD COLUMN 'ssh_address' TEXT");
database.execSQL("ALTER TABLE 'Devices' ADD COLUMN 'ssh_port' INTEGER");
database.execSQL("ALTER TABLE 'Devices' ADD COLUMN 'ssh_user' TEXT");
database.execSQL("ALTER TABLE 'Devices' ADD COLUMN 'ssh_password' TEXT");
database.execSQL("ALTER TABLE 'Devices' ADD COLUMN 'ssh_command' TEXT");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.florianisme.wakeonlan.persistence.migrations;

import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;

public class MigrationFrom4To5 extends Migration {

public MigrationFrom4To5() {
super(4, 5);
}

@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// Do nothing
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,33 @@ public class Device {

public String secureOnPassword;

public Device(int id, String name, String macAddress, String broadcastAddress, int port, String statusIp, String secureOnPassword) {
public boolean remoteShutdownEnabled;

public String sshAddress;

public Integer sshPort;

public String sshUsername;

public String sshPassword;

public String sshCommand;

public Device(int id, String name, String macAddress, String broadcastAddress, int port, String statusIp, String secureOnPassword,
boolean remoteShutdownEnabled, String sshAddress, Integer sshPort, String sshUsername, String sshPassword, String sshCommand) {
this.id = id;
this.name = name;
this.macAddress = macAddress;
this.broadcastAddress = broadcastAddress;
this.port = port;
this.statusIp = statusIp;
this.secureOnPassword = secureOnPassword;
this.remoteShutdownEnabled = remoteShutdownEnabled;
this.sshAddress = sshAddress;
this.sshPort = sshPort;
this.sshUsername = sshUsername;
this.sshPassword = sshPassword;
this.sshCommand = sshCommand;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ public void delete(Device device) {
deviceDao.delete(deviceEntityMapper.modelToEntity(device));
}

public void deleteAll() {
deviceDao.deleteAll();
}

public void replaceAllDevices(Device... devices) {
DeviceEntity[] deviceEntities = Arrays.stream(devices)
.map(deviceEntityMapper::modelToEntity)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ public static ShortcutInfoCompat buildShortcut(Device device, Context context) {
@NonNull
private static Intent buildIntent(Device device, Context context) {
Intent wakeDeviceIntent = new Intent(context, WakeDeviceActivity.class);
wakeDeviceIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
wakeDeviceIntent.setAction(Intent.ACTION_VIEW);

Bundle bundle = new Bundle();
bundle.putInt(WakeDeviceActivity.DEVICE_ID_KEY, device.id);
wakeDeviceIntent.putExtras(bundle);

return wakeDeviceIntent;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

public class DynamicShortcutManager {

public static final int SHORTCUT_AMOUNT_LIMIT = 4;

public void updateShortcuts(Context context, List<Device> devices) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
return;
Expand All @@ -24,6 +26,7 @@ private void publishShortcuts(Context context, List<Device> devices) {
devices.stream()
.sorted((device1, device2) -> Integer.compare(device2.id, device1.id))
.map(device -> DeviceShortcutMapper.buildShortcut(device, context))
.limit(SHORTCUT_AMOUNT_LIMIT)
.forEach(shortcut -> ShortcutManagerCompat.pushDynamicShortcut(context, shortcut));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package de.florianisme.wakeonlan.shutdown;

import android.util.Log;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.Security;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import de.florianisme.wakeonlan.persistence.models.Device;
import de.florianisme.wakeonlan.shutdown.listener.IgnoringShutdownExecutorListener;
import de.florianisme.wakeonlan.shutdown.listener.ShutdownExecutorListener;

public class ShutdownExecutor {

private static final Executor executor = Executors.newSingleThreadExecutor();

static {
// Override Android's BC implementation with official BC Provider
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}

public static void shutdownDevice(Device device, ShutdownExecutorListener shutdownExecutorListener) {
Optional<ShutdownModel> optionalShutdownModel = ShutdownModelFactory.fromDevice(device);

if (!optionalShutdownModel.isPresent()) {
Log.w(ShutdownExecutor.class.getSimpleName(), "Can not shutdown device. Not all required fields were set");
shutdownExecutorListener.onGeneralError(new IllegalArgumentException("Can not shutdown device. Not all required fields were set"), null);
return;
}

ShutdownModel shutdownModel = optionalShutdownModel.get();
ShutdownRunnable shutdownRunnable = new ShutdownRunnable(shutdownModel, shutdownExecutorListener);

executor.execute(shutdownRunnable);
}

public static void shutdownDevice(Device device) {
shutdownDevice(device, new IgnoringShutdownExecutorListener());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package de.florianisme.wakeonlan.shutdown;

public class ShutdownModel {

private final String sshAddress;
private final int sshPort;
private final String username;
private final String password;
private final String command;

public ShutdownModel(String sshAddress, int sshPort, String username, String password, String command) {
this.sshAddress = sshAddress;
this.sshPort = sshPort;
this.username = username;
this.password = password;
this.command = command;
}

public String getSshAddress() {
return sshAddress;
}

public int getSshPort() {
return sshPort;
}

public String getUsername() {
return username;
}

public String getPassword() {
return password;
}

public String getCommand() {
return command;
}
}
Loading

0 comments on commit 608dcef

Please sign in to comment.