From 9598bf1ec6e934533b24193ff16e15421b38c3fb Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Mon, 15 Nov 2021 16:12:34 +0100 Subject: [PATCH 01/11] update pom.xml Updated OSSRH staging repo (see cryptomator/cryptomator#1910) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9a60185..0922667 100644 --- a/pom.xml +++ b/pom.xml @@ -137,7 +137,7 @@ ossrh Maven Central - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ @@ -149,7 +149,7 @@ true ossrh - https://oss.sonatype.org/ + https://s01.oss.sonatype.org/ true From a7cdfc83808eb9f78eb76cb1c7b454dbb00a40d8 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 18 Jan 2022 14:13:31 +0100 Subject: [PATCH 02/11] bump minimum required JDK version --- .github/workflows/build.yml | 12 ++++-------- .github/workflows/codeql-analysis.yml | 12 ++++-------- .github/workflows/publish-central.yml | 12 ++++-------- .github/workflows/publish-github.yml | 12 ++++-------- pom.xml | 8 ++++---- 5 files changed, 20 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 16ee783..36cb45e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,15 +8,11 @@ jobs: if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: - java-version: 11 - - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- + distribution: 'temurin' + java-version: 17 + cache: 'maven' - name: Ensure to use tagged version if: startsWith(github.ref, 'refs/tags/') run: mvn versions:set --file ./pom.xml -DnewVersion=${GITHUB_REF##*/} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a46ddd6..c95b54d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -18,15 +18,11 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: - java-version: 11 - - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- + distribution: 'temurin' + java-version: 17 + cache: 'maven' - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: diff --git a/.github/workflows/publish-central.yml b/.github/workflows/publish-central.yml index f22b7a9..fee8726 100644 --- a/.github/workflows/publish-central.yml +++ b/.github/workflows/publish-central.yml @@ -13,20 +13,16 @@ jobs: - uses: actions/checkout@v2 with: ref: "refs/tags/${{ github.event.inputs.tag }}" - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: - java-version: 11 + distribution: 'temurin' + java-version: 17 + cache: 'maven' server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml server-username: MAVEN_USERNAME # env variable for username in deploy server-password: MAVEN_PASSWORD # env variable for token in deploy gpg-private-key: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} # Value of the GPG private key to import gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase - - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - name: Enforce project version ${{ github.event.inputs.tag }} run: mvn versions:set -B -DnewVersion=${{ github.event.inputs.tag }} - name: Deploy diff --git a/.github/workflows/publish-github.yml b/.github/workflows/publish-github.yml index c74c504..885c659 100644 --- a/.github/workflows/publish-github.yml +++ b/.github/workflows/publish-github.yml @@ -8,17 +8,13 @@ jobs: if: startsWith(github.ref, 'refs/tags/') # only allow publishing tagged versions steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: - java-version: 11 + distribution: 'temurin' + java-version: 17 + cache: 'maven' gpg-private-key: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} # Value of the GPG private key to import gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase - - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - name: Enforce project version ${{ github.event.release.tag_name }} run: mvn versions:set -B -DnewVersion=${{ github.event.release.tag_name }} - name: Deploy diff --git a/pom.xml b/pom.xml index 0922667..dc00bca 100644 --- a/pom.xml +++ b/pom.xml @@ -42,9 +42,9 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.9.0 - 11 + 17 @@ -72,7 +72,7 @@ true - 11 + 17 @@ -110,7 +110,7 @@ maven-gpg-plugin - 1.6 + 3.0.1 sign-artifacts From a53d887c59bee8f79a6cdfb49f5045033204465e Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 18 Jan 2022 14:14:55 +0100 Subject: [PATCH 03/11] move creation of tray icon to integrations-api this will allow non-awt based tray icons --- src/main/java/module-info.java | 7 +++ .../integrations/tray/ActionItem.java | 4 ++ .../tray/AwtTrayMenuController.java | 45 +++++++++++++++++++ .../integrations/tray/SeparatorItem.java | 4 ++ .../integrations/tray/SubMenuItem.java | 6 +++ .../integrations/tray/TrayMenuController.java | 25 +++++++++++ .../integrations/tray/TrayMenuItem.java | 4 ++ 7 files changed, 95 insertions(+) create mode 100644 src/main/java/org/cryptomator/integrations/tray/ActionItem.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/SeparatorItem.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/SubMenuItem.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java create mode 100644 src/main/java/org/cryptomator/integrations/tray/TrayMenuItem.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 4cadffc..f3381f4 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,6 +1,13 @@ +import org.cryptomator.integrations.tray.AwtTrayMenuController; +import org.cryptomator.integrations.tray.TrayMenuController; + module org.cryptomator.integrations.api { + requires java.desktop; + exports org.cryptomator.integrations.autostart; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.tray; exports org.cryptomator.integrations.uiappearance; + + provides TrayMenuController with AwtTrayMenuController; } \ No newline at end of file diff --git a/src/main/java/org/cryptomator/integrations/tray/ActionItem.java b/src/main/java/org/cryptomator/integrations/tray/ActionItem.java new file mode 100644 index 0000000..383618b --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/ActionItem.java @@ -0,0 +1,4 @@ +package org.cryptomator.integrations.tray; + +public record ActionItem(String title, Runnable action) implements TrayMenuItem { +} diff --git a/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java new file mode 100644 index 0000000..85325ff --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java @@ -0,0 +1,45 @@ +package org.cryptomator.integrations.tray; + + +import java.awt.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public class AwtTrayMenuController implements TrayMenuController { + + private TrayIcon trayIcon; + + @Override + public void showTrayIcon(InputStream iconData, String tooltip) throws IOException { + var image = Toolkit.getDefaultToolkit().createImage(iconData.readAllBytes()); + trayIcon = new TrayIcon(image, tooltip); + } + + @Override + public void setTrayMenu(List items) { + if (trayIcon != null) { + var menu = new PopupMenu(); + addChildren(menu, items); + trayIcon.setPopupMenu(menu); + } + } + + private void addChildren(Menu menu, List items) { + for (var item : items) { + // TODO: use Pattern Matching for switch, once available + if (item instanceof ActionItem a) { + var menuItem = new MenuItem(a.title()); + menuItem.addActionListener(evt -> a.action().run()); + menu.add(menuItem); + } else if (item instanceof SeparatorItem) { + menu.addSeparator(); + } else if (item instanceof SubMenuItem s) { + var submenu = new Menu(s.title()); + addChildren(submenu, s.items()); + menu.add(submenu); + } + } + } + +} diff --git a/src/main/java/org/cryptomator/integrations/tray/SeparatorItem.java b/src/main/java/org/cryptomator/integrations/tray/SeparatorItem.java new file mode 100644 index 0000000..7a4eab2 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/SeparatorItem.java @@ -0,0 +1,4 @@ +package org.cryptomator.integrations.tray; + +public record SeparatorItem() implements TrayMenuItem { +} diff --git a/src/main/java/org/cryptomator/integrations/tray/SubMenuItem.java b/src/main/java/org/cryptomator/integrations/tray/SubMenuItem.java new file mode 100644 index 0000000..82a65bf --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/SubMenuItem.java @@ -0,0 +1,6 @@ +package org.cryptomator.integrations.tray; + +import java.util.List; + +public record SubMenuItem(String title, List items) implements TrayMenuItem { +} diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java new file mode 100644 index 0000000..b840f53 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java @@ -0,0 +1,25 @@ +package org.cryptomator.integrations.tray; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public interface TrayMenuController { + + /** + * Adds an icon to the system tray. + * + * @param iconData What image to show + * @param tooltip Text shown when hovering + * @throws IOException thrown when interacting with the given iconData + */ + void showTrayIcon(InputStream iconData, String tooltip) throws IOException; + + /** + * Show the given options in the tray menu. + * + * @param items Menu items + */ + void setTrayMenu(List items); + +} diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuItem.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuItem.java new file mode 100644 index 0000000..a174c15 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuItem.java @@ -0,0 +1,4 @@ +package org.cryptomator.integrations.tray; + +public sealed interface TrayMenuItem permits ActionItem, SubMenuItem, SeparatorItem { +} From 9c6c76a8e93b96a01d456296b631704d16da4caf Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 19 Jan 2022 15:39:44 +0100 Subject: [PATCH 04/11] added new annotations for priorization and filtering --- .../integrations/common/OperatingSystem.java | 51 +++++++++++++++++++ .../integrations/common/Priority.java | 23 +++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/main/java/org/cryptomator/integrations/common/OperatingSystem.java create mode 100644 src/main/java/org/cryptomator/integrations/common/Priority.java diff --git a/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java b/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java new file mode 100644 index 0000000..c6ec0e1 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java @@ -0,0 +1,51 @@ +package org.cryptomator.integrations.common; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Restricts the annotated integration provider to one or more operating system(s). + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Repeatable(OperatingSystem.OperatingSystems.class) +public @interface OperatingSystem { + Value value() default Value.UNKNOWN; + + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE}) + @interface OperatingSystems { + OperatingSystem[] value(); + } + + enum Value { + LINUX, + MAC, + WINDOWS, + UNKNOWN; + + private static final String OS_NAME = System.getProperty("os.name").toLowerCase(); + + public static Value current() { + if (OS_NAME.contains("linux")) { + return LINUX; + } else if (OS_NAME.contains("mac")) { + return MAC; + } else if (OS_NAME.contains("windows")) { + return WINDOWS; + } else { + return UNKNOWN; + } + } + + public static boolean isCurrent(OperatingSystem os) { + return current().equals(os.value()); + } + } +} diff --git a/src/main/java/org/cryptomator/integrations/common/Priority.java b/src/main/java/org/cryptomator/integrations/common/Priority.java new file mode 100644 index 0000000..8bb9a00 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/common/Priority.java @@ -0,0 +1,23 @@ +package org.cryptomator.integrations.common; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Integration Priority. + *

+ * If multiple implementations for an integration can be provided, the provider with the highest priority will be used. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface Priority { + int DEFAULT = 0; + int FALLBACK = Integer.MIN_VALUE; + + int value() default DEFAULT; +} From df15e0dbbe13a9c18c786e04154f59c035a3b524 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 19 Jan 2022 15:40:26 +0100 Subject: [PATCH 05/11] added improved ServiceLoader that respects annotations --- .../common/IntegrationsLoader.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java diff --git a/src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java b/src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java new file mode 100644 index 0000000..7415abe --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java @@ -0,0 +1,38 @@ +package org.cryptomator.integrations.common; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Optional; +import java.util.ServiceLoader; + +public class IntegrationsLoader { + + /** + * Loads the best suited service, i.e. the one with the highest priority that is supported. + *

+ * If two services are available with the same priority, it is unspecified which one will be returned. + * + * @param clazz Service class + * @param Type of the service + * @return Highest priority service or empty if no supported service was found + */ + public static Optional load(Class clazz) { + return ServiceLoader.load(clazz) + .stream() + .filter(IntegrationsLoader::isSupportedOperatingSystem) + .sorted(Comparator.comparingInt(IntegrationsLoader::getPriority)) + .map(ServiceLoader.Provider::get) + .findFirst(); + } + + private static int getPriority(ServiceLoader.Provider provider) { + var prio = provider.type().getAnnotation(Priority.class); + return prio == null ? Priority.DEFAULT : prio.value(); + } + + private static boolean isSupportedOperatingSystem(ServiceLoader.Provider provider) { + var annotations = provider.type().getAnnotationsByType(OperatingSystem.class); + return annotations.length == 0 || Arrays.stream(annotations).anyMatch(OperatingSystem.Value::isCurrent); + } + +} From 998423be927ee3cd4acb9bc81833b8127ee5d82f Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 19 Jan 2022 15:50:14 +0100 Subject: [PATCH 06/11] add static provider methods to all API interfaces --- src/main/java/module-info.java | 10 ++++++++++ .../autostart/AutoStartProvider.java | 8 ++++++++ .../integrations/common/IntegrationsLoader.java | 17 ++++++++++++++--- .../keychain/KeychainAccessProvider.java | 8 ++++++++ .../tray/TrayIntegrationProvider.java | 8 ++++++++ .../uiappearance/UiAppearanceProvider.java | 8 ++++++++ 6 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 4cadffc..0f3f469 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,6 +1,16 @@ +import org.cryptomator.integrations.autostart.AutoStartProvider; +import org.cryptomator.integrations.keychain.KeychainAccessProvider; +import org.cryptomator.integrations.tray.TrayIntegrationProvider; +import org.cryptomator.integrations.uiappearance.UiAppearanceProvider; + module org.cryptomator.integrations.api { exports org.cryptomator.integrations.autostart; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.tray; exports org.cryptomator.integrations.uiappearance; + + uses AutoStartProvider; + uses KeychainAccessProvider; + uses TrayIntegrationProvider; + uses UiAppearanceProvider; } \ No newline at end of file diff --git a/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java b/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java index ade5871..80bf638 100644 --- a/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java +++ b/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java @@ -1,7 +1,15 @@ package org.cryptomator.integrations.autostart; +import org.cryptomator.integrations.common.IntegrationsLoader; + +import java.util.Optional; + public interface AutoStartProvider { + static Optional get() { + return IntegrationsLoader.load(AutoStartProvider.class); + } + void enable() throws ToggleAutoStartFailedException; void disable() throws ToggleAutoStartFailedException; diff --git a/src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java b/src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java index 7415abe..f184d8c 100644 --- a/src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java +++ b/src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java @@ -4,6 +4,7 @@ import java.util.Comparator; import java.util.Optional; import java.util.ServiceLoader; +import java.util.stream.Stream; public class IntegrationsLoader { @@ -17,12 +18,22 @@ public class IntegrationsLoader { * @return Highest priority service or empty if no supported service was found */ public static Optional load(Class clazz) { + return loadAll(clazz).findFirst(); + } + + /** + * Loads all suited services ordered by priority in descending order. + * + * @param clazz Service class + * @param Type of the service + * @return An ordered stream of all suited service candidates + */ + public static Stream loadAll(Class clazz) { return ServiceLoader.load(clazz) .stream() .filter(IntegrationsLoader::isSupportedOperatingSystem) - .sorted(Comparator.comparingInt(IntegrationsLoader::getPriority)) - .map(ServiceLoader.Provider::get) - .findFirst(); + .sorted(Comparator.comparingInt(IntegrationsLoader::getPriority).reversed()) + .map(ServiceLoader.Provider::get); } private static int getPriority(ServiceLoader.Provider provider) { diff --git a/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java b/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java index e6ecafc..3a18d66 100644 --- a/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java +++ b/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java @@ -1,10 +1,18 @@ package org.cryptomator.integrations.keychain; +import org.cryptomator.integrations.common.IntegrationsLoader; + +import java.util.stream.Stream; + /** * This is the interface used by Cryptomator to store passwords securely in external keychains, such as system keychains or password managers. */ public interface KeychainAccessProvider { + static Stream get() { + return IntegrationsLoader.loadAll(KeychainAccessProvider.class).filter(KeychainAccessProvider::isSupported); + } + /** * A name to display in UI elements. If required, this should be localized. * diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java b/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java index cf91862..0c330e5 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java @@ -1,7 +1,15 @@ package org.cryptomator.integrations.tray; +import org.cryptomator.integrations.common.IntegrationsLoader; + +import java.util.Optional; + public interface TrayIntegrationProvider { + static Optional get() { + return IntegrationsLoader.load(TrayIntegrationProvider.class); + } + /** * Performs tasks required when the application is no longer showing any window and only accessible via * system tray (or comparable facilities). diff --git a/src/main/java/org/cryptomator/integrations/uiappearance/UiAppearanceProvider.java b/src/main/java/org/cryptomator/integrations/uiappearance/UiAppearanceProvider.java index c97ec31..8dc0e7d 100644 --- a/src/main/java/org/cryptomator/integrations/uiappearance/UiAppearanceProvider.java +++ b/src/main/java/org/cryptomator/integrations/uiappearance/UiAppearanceProvider.java @@ -1,10 +1,18 @@ package org.cryptomator.integrations.uiappearance; +import org.cryptomator.integrations.common.IntegrationsLoader; + +import java.util.Optional; + /** * This is the interface used by Cryptomator to get os specific UI appearances and themes. */ public interface UiAppearanceProvider { + static Optional get() { + return IntegrationsLoader.load(UiAppearanceProvider.class); + } + /** * Gets the best-matching theme for the OS's current L&F. This might be an approximation, as the OS might support more variations than we do. * From 6263463872c02f74341e1f11846ef844c64de207 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 19 Jan 2022 16:06:11 +0100 Subject: [PATCH 07/11] avoid NPE (even though os.name should always be defined on any JVM) --- .../org/cryptomator/integrations/common/OperatingSystem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java b/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java index c6ec0e1..f618ac8 100644 --- a/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java +++ b/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java @@ -30,7 +30,7 @@ enum Value { WINDOWS, UNKNOWN; - private static final String OS_NAME = System.getProperty("os.name").toLowerCase(); + private static final String OS_NAME = System.getProperty("os.name", "").toLowerCase(); public static Value current() { if (OS_NAME.contains("linux")) { From 96e3251a9e8b7c3184fa2c47b1edf637ac1c3211 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 7 Mar 2022 09:11:56 +0100 Subject: [PATCH 08/11] removed fallback implementation (will be part of the main app) --- src/main/java/module-info.java | 5 -- .../tray/AwtTrayMenuController.java | 48 ------------------- 2 files changed, 53 deletions(-) delete mode 100644 src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 529e1fb..2ac9eaf 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,4 +1,3 @@ -import org.cryptomator.integrations.tray.AwtTrayMenuController; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -7,8 +6,6 @@ module org.cryptomator.integrations.api { - requires java.desktop; - exports org.cryptomator.integrations.autostart; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.tray; @@ -19,6 +16,4 @@ uses TrayIntegrationProvider; uses TrayMenuController; uses UiAppearanceProvider; - - provides TrayMenuController with AwtTrayMenuController; } \ No newline at end of file diff --git a/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java deleted file mode 100644 index 0038dd3..0000000 --- a/src/main/java/org/cryptomator/integrations/tray/AwtTrayMenuController.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.cryptomator.integrations.tray; - - -import org.cryptomator.integrations.common.Priority; - -import java.awt.*; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -@Priority(Priority.FALLBACK) -public class AwtTrayMenuController implements TrayMenuController { - - private TrayIcon trayIcon; - - @Override - public void showTrayIcon(InputStream iconData, String tooltip) throws IOException { - var image = Toolkit.getDefaultToolkit().createImage(iconData.readAllBytes()); - trayIcon = new TrayIcon(image, tooltip); - } - - @Override - public void setTrayMenu(List items) { - if (trayIcon != null) { - var menu = new PopupMenu(); - addChildren(menu, items); - trayIcon.setPopupMenu(menu); - } - } - - private void addChildren(Menu menu, List items) { - for (var item : items) { - // TODO: use Pattern Matching for switch, once available - if (item instanceof ActionItem a) { - var menuItem = new MenuItem(a.title()); - menuItem.addActionListener(evt -> a.action().run()); - menu.add(menuItem); - } else if (item instanceof SeparatorItem) { - menu.addSeparator(); - } else if (item instanceof SubMenuItem s) { - var submenu = new Menu(s.title()); - addChildren(submenu, s.items()); - menu.add(submenu); - } - } - } - -} From e4137ffb4d6506bcd1d968fe1b05962882e09a81 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 7 Mar 2022 09:33:43 +0100 Subject: [PATCH 09/11] api fine tuning and documentation --- .../tray/TrayIntegrationProvider.java | 9 +++++++++ .../integrations/tray/TrayMenuController.java | 20 +++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java b/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java index 0c330e5..8650a2f 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayIntegrationProvider.java @@ -4,8 +4,17 @@ import java.util.Optional; +/** + * Allows to perform OS-specific tasks when the app gets minimized to or restored from a tray icon. + */ public interface TrayIntegrationProvider { + /** + * Loads the best-suited TrayIntegrationProvider. + * + * @return preferred TrayIntegrationProvider (if any) + * @since 1.1.0 + */ static Optional get() { return IntegrationsLoader.load(TrayIntegrationProvider.class); } diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java index 199be1b..48833af 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java @@ -7,6 +7,11 @@ import java.util.List; import java.util.Optional; +/** + * Displays a tray icon and menu + * + * @since 1.1.0 + */ public interface TrayMenuController { static Optional get() { @@ -14,19 +19,22 @@ static Optional get() { } /** - * Adds an icon to the system tray. + * Displays an icon on the system tray. * - * @param iconData What image to show - * @param tooltip Text shown when hovering - * @throws IOException thrown when interacting with the given iconData + * @param rawImageData What image to show + * @param defaultAction Action to perform when interacting with the icon directly instead of its menu + * @param tooltip Text shown when hovering + * @throws IOException thrown when interacting with the given rawImageData */ - void showTrayIcon(InputStream iconData, String tooltip) throws IOException; + void showTrayIcon(InputStream rawImageData, Runnable defaultAction, String tooltip) throws IOException; /** * Show the given options in the tray menu. + *

+ * This method may be called multiple times, e.g. when the vault list changes. * * @param items Menu items */ - void setTrayMenu(List items); + void updateTrayMenu(List items); } From de302ae2db57ef22429cbe0374cd2080b3d780eb Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 7 Mar 2022 09:35:11 +0100 Subject: [PATCH 10/11] javadoc --- .../integrations/autostart/AutoStartProvider.java | 6 ++++++ .../cryptomator/integrations/common/OperatingSystem.java | 2 ++ .../java/org/cryptomator/integrations/common/Priority.java | 2 ++ .../integrations/keychain/KeychainAccessProvider.java | 6 ++++++ .../integrations/uiappearance/UiAppearanceProvider.java | 6 ++++++ 5 files changed, 22 insertions(+) diff --git a/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java b/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java index 80bf638..49f6e3a 100644 --- a/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java +++ b/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java @@ -6,6 +6,12 @@ public interface AutoStartProvider { + /** + * Loads the best-suited AutoStartProvider. + * + * @return preferred AutoStartProvider (if any) + * @since 1.1.0 + */ static Optional get() { return IntegrationsLoader.load(AutoStartProvider.class); } diff --git a/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java b/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java index f618ac8..3369011 100644 --- a/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java +++ b/src/main/java/org/cryptomator/integrations/common/OperatingSystem.java @@ -9,6 +9,8 @@ /** * Restricts the annotated integration provider to one or more operating system(s). + * + * @since 1.1.0 */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/org/cryptomator/integrations/common/Priority.java b/src/main/java/org/cryptomator/integrations/common/Priority.java index 8bb9a00..81ee75d 100644 --- a/src/main/java/org/cryptomator/integrations/common/Priority.java +++ b/src/main/java/org/cryptomator/integrations/common/Priority.java @@ -11,6 +11,8 @@ * Integration Priority. *

* If multiple implementations for an integration can be provided, the provider with the highest priority will be used. + * + * @since 1.1.0 */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java b/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java index 3a18d66..ef0cfae 100644 --- a/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java +++ b/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java @@ -9,6 +9,12 @@ */ public interface KeychainAccessProvider { + /** + * Loads all available KeychainAccessProvider. + * + * @return a stream of {@link #isSupported() supported} KeychainAccessProviders + * @since 1.1.0 + */ static Stream get() { return IntegrationsLoader.loadAll(KeychainAccessProvider.class).filter(KeychainAccessProvider::isSupported); } diff --git a/src/main/java/org/cryptomator/integrations/uiappearance/UiAppearanceProvider.java b/src/main/java/org/cryptomator/integrations/uiappearance/UiAppearanceProvider.java index 8dc0e7d..21e805c 100644 --- a/src/main/java/org/cryptomator/integrations/uiappearance/UiAppearanceProvider.java +++ b/src/main/java/org/cryptomator/integrations/uiappearance/UiAppearanceProvider.java @@ -9,6 +9,12 @@ */ public interface UiAppearanceProvider { + /** + * Loads the best-suited UiAppearanceProvider. + * + * @return preferred UiAppearanceProvider (if any) + * @since 1.1.0 + */ static Optional get() { return IntegrationsLoader.load(UiAppearanceProvider.class); } From 70fb01cccfde5211ad590a9ca25f76a65392f0d9 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 7 Mar 2022 09:49:42 +0100 Subject: [PATCH 11/11] added jetbrains annotations --- pom.xml | 9 +++++++++ src/main/java/module-info.java | 2 ++ .../integrations/autostart/AutoStartProvider.java | 3 +++ .../integrations/keychain/KeychainAccessProvider.java | 9 +++++++++ .../integrations/tray/TrayMenuController.java | 2 ++ 5 files changed, 25 insertions(+) diff --git a/pom.xml b/pom.xml index dc00bca..5d03a19 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,15 @@ + + + org.jetbrains + annotations + 23.0.0 + provided + + + diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 2ac9eaf..9d69841 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -6,6 +6,8 @@ module org.cryptomator.integrations.api { + requires static org.jetbrains.annotations; + exports org.cryptomator.integrations.autostart; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.tray; diff --git a/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java b/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java index 49f6e3a..3a71d20 100644 --- a/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java +++ b/src/main/java/org/cryptomator/integrations/autostart/AutoStartProvider.java @@ -1,6 +1,7 @@ package org.cryptomator.integrations.autostart; import org.cryptomator.integrations.common.IntegrationsLoader; +import org.jetbrains.annotations.Blocking; import java.util.Optional; @@ -16,8 +17,10 @@ static Optional get() { return IntegrationsLoader.load(AutoStartProvider.class); } + @Blocking void enable() throws ToggleAutoStartFailedException; + @Blocking void disable() throws ToggleAutoStartFailedException; boolean isEnabled(); diff --git a/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java b/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java index ef0cfae..8116316 100644 --- a/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java +++ b/src/main/java/org/cryptomator/integrations/keychain/KeychainAccessProvider.java @@ -1,6 +1,9 @@ package org.cryptomator.integrations.keychain; import org.cryptomator.integrations.common.IntegrationsLoader; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Blocking; +import org.jetbrains.annotations.Nls; import java.util.stream.Stream; @@ -24,6 +27,7 @@ static Stream get() { * * @return user-friendly name (must not be null or empty) */ + @Nls(capitalization = Nls.Capitalization.Title) String displayName(); /** @@ -35,6 +39,7 @@ static Stream get() { * @deprecated Please use {@link #storePassphrase(String, String, CharSequence)} instead */ @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException; /** @@ -47,6 +52,7 @@ static Stream get() { * @param passphrase The secret to store in this keychain. * @throws KeychainAccessException If storing the password failed */ + @Blocking default void storePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException { storePassphrase(key, passphrase); } @@ -56,6 +62,7 @@ default void storePassphrase(String key, String displayName, CharSequence passph * @return The stored passphrase for the given key or null if no value for the given key could be found. * @throws KeychainAccessException If loading the password failed */ + @Blocking char[] loadPassphrase(String key) throws KeychainAccessException; /** @@ -75,6 +82,7 @@ default void storePassphrase(String key, String displayName, CharSequence passph * @deprecated Please use {@link #changePassphrase(String, String, CharSequence)} instead */ @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException; /** @@ -87,6 +95,7 @@ default void storePassphrase(String key, String displayName, CharSequence passph * @param passphrase The secret to be updated in this keychain. * @throws KeychainAccessException If changing the password failed */ + @Blocking default void changePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException { changePassphrase(key, passphrase); } diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java index 48833af..fadb980 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java @@ -1,6 +1,7 @@ package org.cryptomator.integrations.tray; import org.cryptomator.integrations.common.IntegrationsLoader; +import org.jetbrains.annotations.ApiStatus; import java.io.IOException; import java.io.InputStream; @@ -12,6 +13,7 @@ * * @since 1.1.0 */ +@ApiStatus.Experimental public interface TrayMenuController { static Optional get() {