diff --git a/.gitignore b/.gitignore index 2e2a23f..603b140 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,14 @@ -.gradle -/local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build -/captures -/versions.properties +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 249f321..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Emaily \ No newline at end of file diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml deleted file mode 100644 index 9d4b0e0..0000000 --- a/.idea/codeStyleSettings.xml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..681f41a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..d91f848 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 9a8b7e5..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/copyright/Erik_C__Thauvin.xml b/.idea/copyright/Erik_C__Thauvin.xml deleted file mode 100644 index ed13fe2..0000000 --- a/.idea/copyright/Erik_C__Thauvin.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/copyright/Erik_s_Copyright_Notice.xml b/.idea/copyright/Erik_s_Copyright_Notice.xml new file mode 100644 index 0000000..81a0d90 --- /dev/null +++ b/.idea/copyright/Erik_s_Copyright_Notice.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml index 4a1337b..1419e40 100644 --- a/.idea/copyright/profiles_settings.xml +++ b/.idea/copyright/profiles_settings.xml @@ -1,11 +1,3 @@ - - - - - - - + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 8d2df47..ac6b0ae 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,8 +1,10 @@ + diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 7f5b7a4..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 3b31283..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..a5f05cd --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 9c184d0..37a7509 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,43 +1,6 @@ - - - - - - - - - - - - - - - - - - + diff --git a/.idea/modules.xml b/.idea/modules.xml index ba50301..5145ba7 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,8 @@ - - + + \ No newline at end of file diff --git a/.idea/scopes/Java_Source.xml b/.idea/scopes/Java_Source.xml deleted file mode 100644 index 582ea35..0000000 --- a/.idea/scopes/Java_Source.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/Emaily.iml b/Emaily.iml deleted file mode 100644 index fe1b347..0000000 --- a/Emaily.iml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 0000000..2fadd27 --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,27 @@ +Copyright (c) 2020, Erik C. Thauvin (erik@thauvin.net) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of this project nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/app/app.iml b/app/app.iml deleted file mode 100644 index 35469ec..0000000 --- a/app/app.iml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 1d02d0b..373dab9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,41 +1,36 @@ apply plugin: 'com.android.application' -apply plugin: 'versionPlugin' android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" + compileSdkVersion 29 + buildToolsVersion "29.0.3" defaultConfig { applicationId "net.thauvin.erik.android.emaily" - minSdkVersion 14 - targetSdkVersion 23 + minSdkVersion 16 + targetSdkVersion 29 versionCode 2 - versionName "1.1b10" + versionName "1.2.0-beta1" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } - - packagingOptions { - exclude 'META-INF/LICENSE' - exclude 'META-INF/NOTICE' - exclude 'META-INF/ASL2.0' - } - - versionPlugin { - buildTypesMatcher = 'release' - supportBuildNumber = false - - fileNameFormat = '$projectName' - } } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - //compile 'com.android.support:appcompat-v7:22.0.0' - compile 'com.android.support:support-annotations:23.1.0' + implementation fileTree(dir: "libs", include: ["*.jar"]) + //implementation 'androidx.appcompat:appcompat:1.1.0' + //implementation 'androidx.preference:preference:1.1.1' + + implementation 'net.thauvin.erik:bitly-shorten:0.9.2' + implementation 'net.thauvin.erik:isgd-shorten:0.9.1' + + testImplementation 'junit:junit:4.13' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } diff --git a/app/libs/bitlyj-2.0.0.jar b/app/libs/bitlyj-2.0.0.jar deleted file mode 100644 index 7c6558f..0000000 Binary files a/app/libs/bitlyj-2.0.0.jar and /dev/null differ diff --git a/app/libs/google-api-client-1.7.0-beta.jar b/app/libs/google-api-client-1.7.0-beta.jar deleted file mode 100644 index ee8281b..0000000 Binary files a/app/libs/google-api-client-1.7.0-beta.jar and /dev/null differ diff --git a/app/libs/google-api-client-android2-1.7.0-beta.jar b/app/libs/google-api-client-android2-1.7.0-beta.jar deleted file mode 100644 index f4417ed..0000000 Binary files a/app/libs/google-api-client-android2-1.7.0-beta.jar and /dev/null differ diff --git a/app/libs/google-api-urlshortener-v1-rev2-java-1.4.0-beta.jar b/app/libs/google-api-urlshortener-v1-rev2-java-1.4.0-beta.jar deleted file mode 100644 index 1257ade..0000000 Binary files a/app/libs/google-api-urlshortener-v1-rev2-java-1.4.0-beta.jar and /dev/null differ diff --git a/app/libs/google-http-client-1.7.0-beta.jar b/app/libs/google-http-client-1.7.0-beta.jar deleted file mode 100644 index 591be28..0000000 Binary files a/app/libs/google-http-client-1.7.0-beta.jar and /dev/null differ diff --git a/app/libs/google-http-client-android2-1.7.0-beta.jar b/app/libs/google-http-client-android2-1.7.0-beta.jar deleted file mode 100644 index 68d95b7..0000000 Binary files a/app/libs/google-http-client-android2-1.7.0-beta.jar and /dev/null differ diff --git a/app/libs/google-http-client-android3-1.7.0-beta.jar b/app/libs/google-http-client-android3-1.7.0-beta.jar deleted file mode 100644 index f8add82..0000000 Binary files a/app/libs/google-http-client-android3-1.7.0-beta.jar and /dev/null differ diff --git a/app/libs/google-oauth-client-1.7.0-beta.jar b/app/libs/google-oauth-client-1.7.0-beta.jar deleted file mode 100644 index e431110..0000000 Binary files a/app/libs/google-oauth-client-1.7.0-beta.jar and /dev/null differ diff --git a/app/libs/gson-2.1.jar b/app/libs/gson-2.1.jar deleted file mode 100644 index 83c5c99..0000000 Binary files a/app/libs/gson-2.1.jar and /dev/null differ diff --git a/app/libs/guava-11.0.1.jar b/app/libs/guava-11.0.1.jar deleted file mode 100644 index af4a383..0000000 Binary files a/app/libs/guava-11.0.1.jar and /dev/null differ diff --git a/app/libs/jackson-core-asl-1.9.4.jar b/app/libs/jackson-core-asl-1.9.4.jar deleted file mode 100644 index 8ad2d81..0000000 Binary files a/app/libs/jackson-core-asl-1.9.4.jar and /dev/null differ diff --git a/app/libs/jsr305-1.3.9.jar b/app/libs/jsr305-1.3.9.jar deleted file mode 100644 index a9afc66..0000000 Binary files a/app/libs/jsr305-1.3.9.jar and /dev/null differ diff --git a/app/libs/protobuf-java-2.2.0.jar b/app/libs/protobuf-java-2.2.0.jar deleted file mode 100644 index 7a0ccde..0000000 Binary files a/app/libs/protobuf-java-2.2.0.jar and /dev/null differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 8fa57da..f1b4245 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,82 +1,21 @@ # Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in C:\Users\erik\AppData\Local\Android\android-sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html -# Add any project specific keep options here: - # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} --optimizationpasses 5 --dontusemixedcaseclassnames --dontskipnonpubliclibraryclasses --dontpreverify --verbose --optimizations !code/simplification/arithmetic,!field/*,!class/merging/* --keep public class * extends android.app.Activity --keep public class * extends android.app.Application --keep public class * extends android.app.Service --keep public class * extends android.content.BroadcastReceiver --keep public class * extends android.content.ContentProvider --keep public class * extends android.app.backup.BackupAgentHelper --keep public class * extends android.preference.Preference --keep public class com.android.vending.licensing.ILicensingService +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable --keepclasseswithmembernames class * { - native ; -} - --keepclasseswithmembers class * { - public (android.content.Context, android.util.AttributeSet); -} - --keepclasseswithmembers class * { - public (android.content.Context, android.util.AttributeSet, int); -} - --keepclassmembers class * extends android.app.Activity { - public void *(android.view.View); -} - --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); -} - --keep class * implements android.os.Parcelable { - public static final android.os.Parcelable$Creator *; -} - -# Needed by google-http-client to keep generic types and @Key annotations accessed via reflection - --keepclassmembers class * { - @com.google.api.client.util.Key ; -} - -# Needed just to be safe in terms of keeping Google API service model classes - --keep class com.google.api.services.*.model.* - --keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault - -# Needed by Guava - --dontwarn sun.misc.Unsafe - -# See https://groups.google.com/forum/#!topic/guava-discuss/YCZzeCiIVoI --dontwarn com.google.common.collect.MinMaxPriorityQueue - -# Emaily --keep class com.google.api.client.googleapis.json.* --dontwarn org.apache.commons.codec.binary.StringUtils --dontwarn org.apache.commons.codec.binary.Base64 --dontwarn com.google.api.client.http.apache.* \ No newline at end of file +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/net/thauvin/erik/android/emaily/ExampleInstrumentedTest.java b/app/src/androidTest/java/net/thauvin/erik/android/emaily/ExampleInstrumentedTest.java new file mode 100644 index 0000000..6d1e030 --- /dev/null +++ b/app/src/androidTest/java/net/thauvin/erik/android/emaily/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package net.thauvin.erik.android.emaily; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("net.thauvin.erik.android.emaily", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3b71d09..4da6182 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,37 +1,39 @@ + package="net.thauvin.erik.android.emaily"> - - - + + + - + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="true" + android:theme="@style/Emaily"> + - + - + - + + android:name=".EmailyPrefs" + android:label="@string/app_name"> - + - + - - \ No newline at end of file + diff --git a/app/src/main/java/net/thauvin/erik/android/emaily/BitlyCredsDialog.java b/app/src/main/java/net/thauvin/erik/android/emaily/BitlyCredsDialog.java index 8f0f837..03f8b5f 100644 --- a/app/src/main/java/net/thauvin/erik/android/emaily/BitlyCredsDialog.java +++ b/app/src/main/java/net/thauvin/erik/android/emaily/BitlyCredsDialog.java @@ -1,35 +1,33 @@ /* - * @(#)BitlyCredsDialog.java + * BitlyCredsDialog.java * - * Copyright (c) 2011-2015 Erik C. Thauvin (http://erik.thauvin.net/) + * Copyright (c) 2011-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * modification, are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * - * Neither the name of the authors nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package net.thauvin.erik.android.emaily; @@ -44,19 +42,16 @@ import android.util.AttributeSet; import android.view.View; import android.widget.EditText; import android.widget.TextView; -import android.support.annotation.NonNull; /** * The BitlyCredsDialog class implements a bit.ly credential dialog. * * @author Erik C. Thauvin - * @created March 28, 2012 * @since 1.0 */ public class BitlyCredsDialog extends DialogPreference { private final Context context; - private EditText username; private EditText apikey; public BitlyCredsDialog(Context context, AttributeSet attrs) @@ -67,16 +62,14 @@ public class BitlyCredsDialog extends DialogPreference } @Override - protected void onBindDialogView(@NonNull View view) + protected void onBindDialogView(View view) { super.onBindDialogView(view); final SharedPreferences sharedPrefs = getSharedPreferences(); - username = (EditText) view.findViewById(R.id.bitly_username_edit); - apikey = (EditText) view.findViewById(R.id.bitly_apikey_edit); - final TextView textFld = (TextView) view.findViewById(R.id.bitly_text_fld); + apikey = view.findViewById(R.id.bitly_apikey_edit); + final TextView textFld = view.findViewById(R.id.bitly_text_fld); - username.setText(sharedPrefs.getString(context.getString(R.string.prefs_key_bitly_username), "")); apikey.setText(sharedPrefs.getString(context.getString(R.string.prefs_key_bitly_apikey), "")); textFld.setOnClickListener(new View.OnClickListener() @@ -99,9 +92,9 @@ public class BitlyCredsDialog extends DialogPreference { final SharedPreferences sharedPrefs = getSharedPreferences(); final Editor editor = sharedPrefs.edit(); - editor.putString(context.getString(R.string.prefs_key_bitly_username), username.getText().toString()); + editor.putString(context.getString(R.string.prefs_key_bitly_apikey), apikey.getText().toString()); - editor.commit(); + editor.apply(); } } diff --git a/app/src/main/java/net/thauvin/erik/android/emaily/Emaily.java b/app/src/main/java/net/thauvin/erik/android/emaily/Emaily.java index 727a865..e38d87c 100644 --- a/app/src/main/java/net/thauvin/erik/android/emaily/Emaily.java +++ b/app/src/main/java/net/thauvin/erik/android/emaily/Emaily.java @@ -1,95 +1,65 @@ /* - * @(#)Emaily.java + * Emaily.java * - * Copyright (c) 2011-2015 Erik C. Thauvin (http://erik.thauvin.net/) + * Copyright (c) 2011-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * modification, are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * - * Neither the name of the authors nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package net.thauvin.erik.android.emaily; -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerCallback; -import android.accounts.AccountManagerFuture; -import android.accounts.OperationCanceledException; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.content.pm.PackageManager.NameNotFoundException; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.text.ClipboardManager; -import android.text.Html; import android.util.Log; import android.widget.Toast; -import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager; -import com.google.api.client.googleapis.json.GoogleJsonError; -import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.http.json.JsonHttpRequest; -import com.google.api.client.http.json.JsonHttpRequestInitializer; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson.JacksonFactory; -import com.google.api.services.urlshortener.Urlshortener; -import com.google.api.services.urlshortener.UrlshortenerRequest; -import com.google.api.services.urlshortener.model.Url; +import net.thauvin.erik.bitly.Bitly; +import net.thauvin.erik.isgd.Isgd; -import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; -import java.util.Date; -import static com.rosaloves.bitlyj.Bitly.as; -import static com.rosaloves.bitlyj.Bitly.shorten; /** * The Emaily class implements a URL shortener intent. * * @author Erik C. Thauvin - * @created Oct 11, 2011 * @since 1.0 */ -public class Emaily extends Activity -{ - private static final String ACCOUNT_TYPE = "com.google"; - private static final String OAUTH_URL = "oauth2:https://www.googleapis.com/auth/urlshortener"; - +public class Emaily extends Activity { private String appName; private SharedPreferences sharedPrefs; @@ -97,218 +67,34 @@ public class Emaily extends Activity * Validates a string. * * @param s The string to validate. - * @return returns true if the string is not empty or null, false otherwise. + * @return returns true if the string is not empty or null, false + * otherwise. */ - public static boolean isValid(String s) - { + public static boolean isValid(String s) { return (s != null) && (!s.trim().isEmpty()); } - @SuppressLint("CommitPrefEdits") - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - final Intent intent = getIntent(); - - appName = getString(R.string.app_name); - sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - - if (Intent.ACTION_SEND.equals(intent.getAction())) - { - final boolean isGoogl = getBoolPref(R.string.prefs_key_googl_enabled, true); - - if (isGoogl) - { - final String account = getPref(R.string.prefs_key_googl_account); - - if (isValid(account)) - { - startEmailyTask(intent, new Account(account, ACCOUNT_TYPE), false); - } - else - { - final AlertDialog.Builder builder = new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); - builder.setTitle(R.string.dialog_accounts_title); - - final Account[] accounts = AccountManager.get(this).getAccountsByType(ACCOUNT_TYPE); - final int size = accounts.length; - if (size > 0) - { - if (size == 1) - { - startEmailyTask(intent, accounts[0], false); - } - else - { - final CharSequence[] names = new CharSequence[size]; - for (int i = 0; i < size; i++) - { - names[i] = accounts[i].name; - } - - builder.setSingleChoiceItems(names, 0, new DialogInterface.OnClickListener() - { - @Override - public void onClick(DialogInterface dialog, int which) - { - dialog.dismiss(); - - final Editor editor = sharedPrefs.edit(); - editor.putString(getString(R.string.prefs_key_googl_account), names[which].toString()); - editor.putLong(getString(R.string.prefs_key_googl_token_expiry), 0L); - editor.commit(); - - startEmailyTask(intent, accounts[which], false); - } - - }); - - builder.create().show(); - } - } - else - { - //noinspection ConstantConditions - startEmailyTask(intent, isGoogl, false); - } - } - } - else - { - //noinspection ConstantConditions - startEmailyTask(intent, isGoogl, false); - } - } - else - { - Emaily.this.finish(); - } - - } - /** - * Starts the task. + * Returns the value of the specified shared reference based on the specified string id. * - * @param intent The original intent. - * @param isGoogl The goo.gl flag. - * @param isRetry The retry flag. + * @param id The string id. + * @param defaultValue The default value, used if the preference is empty. + * @return The preference value. */ - private void startEmailyTask(final Intent intent, final boolean isGoogl, final boolean isRetry) - { - final EmailyTask task; - - if (isGoogl) - { - //noinspection ConstantConditions - task = new EmailyTask(getPref(R.string.prefs_key_googl_account), getPref(R.string.prefs_key_googl_token), isGoogl, - getBoolPref(R.string.prefs_key_html_chkbox), isRetry); - } - else - { - //noinspection ConstantConditions - task = new EmailyTask(getPref(R.string.prefs_key_bitly_username), getPref(R.string.prefs_key_bitly_apikey), isGoogl, - getBoolPref(R.string.prefs_key_html_chkbox), isRetry); - } - - task.execute(intent); + @SuppressWarnings("SameParameterValue") + private boolean getBoolPref(int id, boolean defaultValue) { + return sharedPrefs.getBoolean(getString(id), defaultValue); } /** - * Starts the task. - * - * @param intent The original intent. - * @param account The account. - * @param isRetry The retry flag. - */ - private void startEmailyTask(final Intent intent, final Account account, final boolean isRetry) - { - final GoogleAccountManager googleAccountManager = new GoogleAccountManager(Emaily.this); - - final long expiry = sharedPrefs.getLong(getString(R.string.prefs_key_googl_token_expiry), 0L); - final long now = System.currentTimeMillis(); - final long maxLife = (60L * 55L) * 1000L; // 55 minutes - - Log.d(appName, "Token Expires: " + new Date(expiry)); - - if (expiry >= (now + maxLife) || expiry <= now) - { - final String token = getPref(R.string.prefs_key_googl_token); - if (isValid(token)) - { - googleAccountManager.manager.invalidateAuthToken(ACCOUNT_TYPE, token); - - Log.d(appName, "Token Invalidated: " + token); - } - } - - googleAccountManager.manager.getAuthToken(account, OAUTH_URL, null, Emaily.this, new AccountManagerCallback() - { - @SuppressLint("CommitPrefEdits") - @Override - public void run(AccountManagerFuture future) - { - try - { - final String token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN); - final Editor editor = sharedPrefs.edit(); - final long now = System.currentTimeMillis(); - - final long expires; - if (expiry < now) - { - expires = now + maxLife; - } - else - { - expires = expiry; - } - - editor.putLong(getString(R.string.prefs_key_googl_token_expiry), expires); - editor.putString(getString(R.string.prefs_key_googl_token), token); - editor.commit(); - - Log.d(appName, account.toString()); - Log.d(appName, "Token: " + token); - Log.d(appName, "Expires: " + new Date(expires)); - - startEmailyTask(intent, true, isRetry); - - } - catch (OperationCanceledException e) - { - Log.e(appName, "Auth token request has been canceled.", e); - } - catch (Exception e) - { - Log.e(appName, "Exception while requesting the auth token.", e); - } - } - }, null); - } - - /** - * Retries the task. - * - * @param intent The original intent. - */ - @SuppressLint("CommitPrefEdits") - private void retry(final Intent intent) - { - sharedPrefs.edit().putLong(getString(R.string.prefs_key_googl_token_expiry), 0L).commit(); - - startEmailyTask(intent, new Account(getPref(R.string.prefs_key_googl_account), ACCOUNT_TYPE), true); - } - - /** - * Returns the value of the specified shared reference based on the specified string id. The default value is an empty string. + * Returns the value of the specified shared reference based on the specified string id. The + * default value is an empty string. * * @param id The string id. * @return The preference value. */ - private String getPref(int id) - { + @SuppressWarnings("SameParameterValue") + private String getPref(int id) { return getPref(id, ""); } @@ -319,276 +105,216 @@ public class Emaily extends Activity * @param defaultValue The default value, used if the preference is empty. * @return The preference value. */ - private String getPref(int id, String defaultValue) - { + @SuppressWarnings("SameParameterValue") + private String getPref(int id, String defaultValue) { return sharedPrefs.getString(getString(id), defaultValue); } - /** - * Returns the value of the specified shared reference based on the specified string id. The default value is false. - * - * @param id The string id. - * @return The preference value. - */ - private boolean getBoolPref(int id) - { - return getBoolPref(id, false); + @SuppressLint("CommitPrefEdits") + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Intent intent = getIntent(); + + appName = getString(R.string.app_name); + sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + + if (Intent.ACTION_SEND.equals(intent.getAction())) { + final boolean isGd = getBoolPref(R.string.prefs_key_isgd_enabled, true); + startEmailyTask(intent, isGd); + } else { + Emaily.this.finish(); + } + } /** - * Returns the value of the specified shared reference based on the specified string id. + * Starts the task. * - * @param id The string id. - * @param defaultValue The default value, used if the preference is empty. - * @return The preference value. + * @param intent The original intent. + * @param isGd The is.gd flag. */ - private boolean getBoolPref(int id, boolean defaultValue) - { - return sharedPrefs.getBoolean(getString(id), defaultValue); + private void startEmailyTask(final Intent intent, final boolean isGd) { + final EmailyTask task; + + if (isGd) { + //noinspection ConstantConditions + task = new EmailyTask("", isGd); + } else { + //noinspection ConstantConditions + task = new EmailyTask(getPref(R.string.prefs_key_bitly_apikey), isGd); + } + + task.execute(intent); + } + + + /** + * The EmailyResult class. + */ + private static class EmailyResult { + private final Intent intent; + private int code = 0; + private String message; + + public EmailyResult(Intent intent) { + this.intent = intent; + } + + public int getCode() { + return code; + } + + @SuppressWarnings("unused") + public Intent getIntent() { + return intent; + } + + public String getMessage() { + if (isValid(message)) { + return message; + } else { + return ""; + } + } + + public boolean hasError() { + return code != 0; + } + + public void setCode(int code) { + this.code = code; + } + + public void setMessage(String message) { + this.message = message; + } } /** * The EmailyTask class. */ - private class EmailyTask extends AsyncTask - { - private final ProgressDialog dialog = new ProgressDialog(Emaily.this, AlertDialog.THEME_DEVICE_DEFAULT_DARK); - private final String username; + @SuppressLint("StaticFieldLeak") + private class EmailyTask extends AsyncTask { + private final ProgressDialog dialog = + new ProgressDialog(Emaily.this, AlertDialog.THEME_DEVICE_DEFAULT_DARK); + private final boolean isGd; private final String keytoken; - private final boolean isGoogl; - private final boolean isHtml; - private final boolean isRetry; - public EmailyTask(String username, String keytoken, boolean isGoogl, boolean isHtml, boolean isRetry) - { - this.username = username; + public EmailyTask(String keytoken, boolean isGd) { this.keytoken = keytoken; - this.isGoogl = isGoogl; - this.isHtml = isHtml; - this.isRetry = isRetry; + this.isGd = isGd; } @Override - protected EmailyResult doInBackground(Intent... intent) - { + protected EmailyResult doInBackground(Intent... intent) { final EmailyResult result = new EmailyResult(intent[0]); final Intent emailIntent = new Intent(Intent.ACTION_SEND); - - if (isHtml) - { - emailIntent.setType("text/html"); - } - else - { - emailIntent.setType("text/plain"); - } - - final Bundle extras = intent[0].getExtras(); + final String pageUrl; + final String pageTitle; + + emailIntent.setType("text/plain"); + + if (extras != null) { + pageUrl = extras.getString(Intent.EXTRA_TEXT); + pageTitle = extras.getString(Intent.EXTRA_SUBJECT); + } else { + pageTitle = null; + pageUrl = null; + } - final String pageUrl = extras.getString(Intent.EXTRA_TEXT); - final String pageTitle = extras.getString(Intent.EXTRA_SUBJECT); final StringBuilder textBefore = new StringBuilder(); - if (isValid(pageTitle)) - { + if (isValid(pageTitle)) { emailIntent.putExtra(Intent.EXTRA_SUBJECT, pageTitle); } - final boolean hasCredentials = isValid(username) && isValid(keytoken); final StringBuilder shortUrl = new StringBuilder(); - if (isValid(pageUrl)) - { - final HttpTransport transport = new NetHttpTransport(); - final JsonFactory jsonFactory = new JacksonFactory(); - - String version = ""; - - try - { - version = '/' + getPackageManager().getPackageInfo(getPackageName(), 0).versionName; - } - catch (NameNotFoundException ignore) - { - // Do nothing; - } - - final Url toInsert = new Url(); - + if (isValid(pageUrl)) { final String[] splits = pageUrl.split("\\s"); - for (String item : splits) - { - try - { + for (String item : splits) { + try { new URL(item.trim()); - if (isGoogl || !hasCredentials) - { - Log.d(appName, "goo.gl -> " + item); - - final Urlshortener shortener = Urlshortener.builder(transport, jsonFactory).setApplicationName(appName + version) - .setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() - { - @Override - public void initialize(JsonHttpRequest request) throws IOException - { - UrlshortenerRequest shortnerRequest = (UrlshortenerRequest) request; - - shortnerRequest.setKey(getString(R.string.secret_apikey)); - - if (isValid(keytoken)) - { - shortnerRequest.setOauthToken(keytoken); - - } - shortnerRequest.put("client_id", getString(R.string.secret_client_id)); - shortnerRequest.put("client_secret", getString(R.string.secret_client_secret)); - } - }).build(); - - toInsert.setLongUrl(item.trim()); - - try - { - final Url shortened = shortener.url().insert(toInsert).execute(); - - shortUrl.append(shortened.getId()); - } - catch (GoogleJsonResponseException e) - { - result.setCode(R.string.alert_error); - - final GoogleJsonError err = e.getDetails(); - - result.setMessage(err.message); - - if (err.code == 401) - { - if (!isRetry) - { - result.setRetry(true); - } - } - - Log.e(appName, "Exception while shortening '" + item + "' via goo.gl.", e); - } - catch (UnknownHostException e) - { - result.setCode(R.string.alert_nohost); - result.setMessage(e.getMessage()); - - Log.e(appName, "UnknownHostException while shortening '" + item + "' via goo.gl.", e); - } - catch (IOException e) - { - result.setCode(R.string.alert_error); - result.setMessage(e.getMessage()); - - Log.e(appName, "IOException while shortening '" + item + "' via goo.gl.", e); - } - } - else - { - Log.d(appName, "bit.ly -> " + item); - - try - { - shortUrl.append(as(username, keytoken).call(shorten(item.trim())).getShortUrl()); - } - catch (Exception e) - { - final Throwable cause = e.getCause(); - - if (cause != null && cause instanceof UnknownHostException) - { - result.setCode(R.string.alert_nohost); - result.setMessage(cause.getMessage()); - } - else - { + try { + if (isGd) { + Log.d(appName, "is.gd -> " + item); + shortUrl.append(Isgd.shorten(item)); + } else { + final Bitly bitly = new Bitly(keytoken); + shortUrl.append(bitly.bitlinks().shorten(item)); + if (shortUrl.toString().equals(item)) { result.setCode(R.string.alert_error); - result.setMessage(e.getMessage()); + //@TODO fixme + result.setMessage("TBD"); } - - Log.e(appName, "Exception while shortening '" + item + "' via bit.ly.", e); } + } catch (Exception e) { + final Throwable cause = e.getCause(); - break; + if (cause instanceof UnknownHostException) { + result.setCode(R.string.alert_nohost); + result.setMessage(cause.getMessage()); + } else { + result.setCode(R.string.alert_error); + result.setMessage(e.getMessage()); + } } break; - } - catch (MalformedURLException mue) - { + } catch (MalformedURLException mue) { Log.d(appName, "Attempted to process an invalid URL: " + item, mue); - if (textBefore.length() > 0) - { + if (textBefore.length() > 0) { textBefore.append(" "); } textBefore.append(item); } } - } - else - { + } else { result.setCode(R.string.alert_nocreds); } - if (!result.isRetry()) - { - if (shortUrl.length() > 0) - { - if (isHtml) - { - emailIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml("" + shortUrl + "")); - } - else - { - emailIntent.putExtra(Intent.EXTRA_TEXT, shortUrl.toString()); - } + if (shortUrl.length() > 0) { + emailIntent.putExtra(Intent.EXTRA_TEXT, shortUrl.toString()); + Log.d(appName, "URL: " + emailIntent.getStringExtra(Intent.EXTRA_TEXT)); - if (!isValid(pageTitle) && textBefore.length() > 0) - { - emailIntent.putExtra(Intent.EXTRA_SUBJECT, textBefore.toString()); - } + if (!isValid(pageTitle) && textBefore.length() > 0) { + emailIntent.putExtra(Intent.EXTRA_SUBJECT, textBefore.toString()); } - else - { + } else { + if (extras != null) { final CharSequence chars = extras.getCharSequence(Intent.EXTRA_TEXT); - if (chars.length() > 0) - { + if (chars != null && chars.length() > 0) { emailIntent.putExtra(Intent.EXTRA_TEXT, chars); - } - else if (isValid(pageUrl)) - { + } else if (isValid(pageUrl)) { emailIntent.putExtra(Intent.EXTRA_TEXT, pageUrl); } } + } - try - { - startActivity(emailIntent); - } - catch (android.content.ActivityNotFoundException ignore) - { - if (!result.hasError() && shortUrl.length() > 0) - { - @SuppressWarnings("deprecation") - final ClipboardManager clip = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + try { + startActivity(emailIntent); + } catch (android.content.ActivityNotFoundException ignore) { + if (!result.hasError() && shortUrl.length() > 0) { + @SuppressWarnings("deprecation") + final ClipboardManager clip = + (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + if (clip != null) { + //noinspection deprecation clip.setText(shortUrl); + } - result.setCode(R.string.alert_notfound_clip); - } - else - { - result.setCode(R.string.alert_notfound); - } + result.setCode(R.string.alert_notfound_clip); + } else { + result.setCode(R.string.alert_notfound); } } @@ -596,108 +322,29 @@ public class Emaily extends Activity } @Override - protected void onPostExecute(EmailyResult result) - { - if (this.dialog.isShowing()) - { - this.dialog.dismiss(); - } - - if (result.isRetry()) - { - Emaily.this.retry(result.getIntent()); - } - else - { - if (result.hasError()) - { - Toast.makeText( - getApplicationContext(), - getString(result.getCode(), result.getMessage(), isGoogl ? getString(R.string.prefs_googl_title) - : getString(R.string.prefs_bitly_title)), Toast.LENGTH_LONG).show(); - - } - - Emaily.this.finish(); - } + protected void onPreExecute() { + this.dialog.setMessage(getString(R.string.progress_msg)); + this.dialog.show(); } @Override - protected void onPreExecute() - { - if (isRetry) - { - this.dialog.setMessage(getString(R.string.progress_msg_retry)); - } - else - { - this.dialog.setMessage(getString(R.string.progress_msg)); + protected void onPostExecute(EmailyResult result) { + if (this.dialog.isShowing()) { + this.dialog.dismiss(); } - this.dialog.show(); + if (result.hasError()) { + Toast.makeText( + getApplicationContext(), + getString(result.getCode(), + result.getMessage(), + isGd ? getString(R.string.prefs_isgd_title) + : getString(R.string.prefs_bitly_title)), Toast.LENGTH_LONG) + .show(); + + } + + Emaily.this.finish(); } } - - /** - * The EmailyResult class. - */ - private class EmailyResult - { - private final Intent intent; - private int code = 0; - private String message; - private boolean retry = false; - - public EmailyResult(Intent intent) - { - this.intent = intent; - } - - public int getCode() - { - return code; - } - - public void setCode(int code) - { - this.code = code; - } - - public String getMessage() - { - if (isValid(message)) - { - return message; - } - else - { - return ""; - } - } - - public void setMessage(String message) - { - this.message = message; - } - - public Intent getIntent() - { - return intent; - } - - public boolean hasError() - { - return code != 0; - } - - public boolean isRetry() - { - return retry; - } - - public void setRetry(boolean retry) - { - this.retry = retry; - } - } -} \ No newline at end of file +} diff --git a/app/src/main/java/net/thauvin/erik/android/emaily/EmailyPrefs.java b/app/src/main/java/net/thauvin/erik/android/emaily/EmailyPrefs.java index 54b6a93..8b45930 100644 --- a/app/src/main/java/net/thauvin/erik/android/emaily/EmailyPrefs.java +++ b/app/src/main/java/net/thauvin/erik/android/emaily/EmailyPrefs.java @@ -1,40 +1,36 @@ /* - * @(#)EmailyPrefs.java + * EmailyPrefs.java * - * Copyright (c) 2011-2015 Erik C. Thauvin (http://erik.thauvin.net/) + * Copyright (c) 2011-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * modification, are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * - * Neither the name of the authors nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package net.thauvin.erik.android.emaily; -import java.util.Locale; - import android.annotation.SuppressLint; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -48,123 +44,99 @@ import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; +import java.util.Locale; + /** * The EmailyPrefs class implements a preferences screen. - * + * * @author Erik C. Thauvin - * @created Oct 11, 2011 * @since 1.0 */ +@SuppressLint("ExportedPreferenceActivity") @SuppressWarnings("deprecation") -public class EmailyPrefs extends PreferenceActivity implements OnSharedPreferenceChangeListener -{ - private SharedPreferences sharedPrefs; +public class EmailyPrefs extends PreferenceActivity implements OnSharedPreferenceChangeListener { + private BitlyCredsDialog bitlyCreds; + private CheckBoxPreference isgdBox; + private SharedPreferences sharedPrefs; - private CheckBoxPreference googlBox; - private BitlyCredsDialog bitlyCreds; + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.prefs); - addPreferencesFromResource(R.xml.prefs); + sharedPrefs = getPreferenceScreen().getSharedPreferences(); - sharedPrefs = getPreferenceScreen().getSharedPreferences(); + isgdBox = (CheckBoxPreference) findPreference(getString(R.string.prefs_key_isgd_chkbox)); + bitlyCreds = (BitlyCredsDialog) findPreference(getString(R.string.prefs_key_bitly_creds)); - googlBox = (CheckBoxPreference) findPreference(getString(R.string.prefs_key_googl_chkbox)); - bitlyCreds = (BitlyCredsDialog) findPreference(getString(R.string.prefs_key_bitly_creds)); + setBitlyCredsSummary(); - setSummary(bitlyCreds, getString(R.string.prefs_key_bitly_username), getString(R.string.prefs_bitly_creds_summary)); - setSummary(googlBox, getString(R.string.prefs_key_googl_account), ""); + if (isgdBox.isChecked()) { + bitlyCreds.setEnabled(false); + } - if (googlBox.isChecked()) - { - bitlyCreds.setEnabled(false); - } + final Preference version = findPreference(getString(R.string.prefs_key_version)); + final PreferenceScreen feedback = + (PreferenceScreen) findPreference(getString(R.string.prefs_key_feedback)); + try { + final String vNumber = + getPackageManager().getPackageInfo(getPackageName(), 0).versionName; - final Preference version = findPreference(getString(R.string.prefs_key_version)); - final PreferenceScreen feedback = (PreferenceScreen) findPreference(getString(R.string.prefs_key_feedback)); - try - { - final String vNumber = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; + version.setTitle(getString(R.string.prefs_version_title) + ' ' + vNumber); - version.setTitle(getString(R.string.prefs_version_title) + ' ' + vNumber); + feedback.getIntent().setData( + Uri.parse(getString(R.string.prefs_feedback_url) + + "?subject=" + + getString(R.string.prefs_feedback_subject, + getString(R.string.app_name), + vNumber, + getString(R.string.prefs_feedback_title) + .toLowerCase(Locale.getDefault()), + Build.MANUFACTURER, + Build.PRODUCT, + Build.VERSION.RELEASE))); - feedback.getIntent().setData( - Uri.parse(getString(R.string.prefs_feedback_url) - + "?subject=" - + getString(R.string.prefs_feedback_subject, getString(R.string.app_name), vNumber, - getString(R.string.prefs_feedback_title).toLowerCase(Locale.getDefault()), Build.MANUFACTURER, - Build.PRODUCT, Build.VERSION.RELEASE))); + } catch (NameNotFoundException ignore) { + // Do nothing. + } + } - } - catch (NameNotFoundException ignore) - { - // Do nothing. - } - } + @Override + protected void onResume() { + super.onResume(); + sharedPrefs.registerOnSharedPreferenceChangeListener(this); + } - @Override - protected void onResume() - { - super.onResume(); - sharedPrefs.registerOnSharedPreferenceChangeListener(this); - } + @Override + protected void onPause() { + super.onPause(); + sharedPrefs.unregisterOnSharedPreferenceChangeListener(this); + } - @Override - protected void onPause() - { - super.onPause(); - sharedPrefs.unregisterOnSharedPreferenceChangeListener(this); - } + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(getString(R.string.prefs_key_bitly_apikey))) { + setBitlyCredsSummary(); + } else if (key.equals(getString(R.string.prefs_key_isgd_chkbox))) { + final boolean checked = isgdBox.isChecked(); - @SuppressLint("CommitPrefEdits") - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) - { - if (key.equals(getString(R.string.prefs_key_bitly_username))) - { - setSummary(bitlyCreds, key, getString(R.string.prefs_bitly_creds_summary)); - } - else if (key.equals(getString(R.string.prefs_key_googl_chkbox))) - { - final boolean checked = googlBox.isChecked(); + bitlyCreds.setEnabled(!checked); - bitlyCreds.setEnabled(!checked); + final Editor editor = sharedPrefs.edit(); + editor.putBoolean(getString(R.string.prefs_key_isgd_enabled), checked); + editor.apply(); + } + } - final Editor editor = sharedPrefs.edit(); - editor.putBoolean(getString(R.string.prefs_key_googl_enabled), checked); - - if (!checked) - { - editor.putString(getString(R.string.prefs_key_googl_account), ""); - editor.putLong(getString(R.string.prefs_key_googl_token_expiry), 0L); - googlBox.setSummary(""); - } - - editor.commit(); - } - } - - /** - * Sets a preference's summary. - * - * @param editPref The preference. - * @param key The preference key. - * @param defValue The default value. - */ - private void setSummary(Preference editPref, String key, String defValue) - { - final String value = sharedPrefs.getString(key, defValue); - - if (Emaily.isValid(value)) - { - editPref.setSummary(value); - } - else - { - editPref.setSummary(defValue); - } - } + /** + * Sets the bit.ly credentials summary. + */ + private void setBitlyCredsSummary() { + if (Emaily.isValid(sharedPrefs.getString(getString(R.string.prefs_key_bitly_apikey), ""))) { + bitlyCreds.setSummary(getString(R.string.prefs_bitly_creds_summary_edit)); + } else { + bitlyCreds.setSummary(getString(R.string.prefs_bitly_creds_summary_default)); + } + } } diff --git a/app/src/main/res/layout/bitlycreds.xml b/app/src/main/res/layout/bitlycreds.xml index b0bf4e5..104b8b3 100644 --- a/app/src/main/res/layout/bitlycreds.xml +++ b/app/src/main/res/layout/bitlycreds.xml @@ -1,66 +1,43 @@ - - - - + android:orientation="vertical" + android:paddingTop="20dip"> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="20dip" + android:layout_marginRight="20dip" + android:gravity="start" + android:text="@string/prefs_bitly_creds_apikey" + android:textAppearance="?android:attr/textAppearanceSmall" /> + android:id="@+id/bitly_apikey_edit" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="20dip" + android:layout_marginRight="20dip" + android:autofillHints="" + android:gravity="fill_horizontal" + android:hint="@string/prefs_bitly_creds_apikey_hint" + android:inputType="textPassword" + android:key="@string/prefs_key_bitly_apikey" + android:scrollHorizontally="true" + android:textAppearance="?android:attr/textAppearanceMedium" /> - - - \ No newline at end of file + android:id="@+id/bitly_text_fld" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:layout_marginTop="20dip" + android:layout_marginBottom="20dip" + android:clickable="true" + android:focusable="true" + android:gravity="center" + android:text="@string/prefs_bitly_creds_noapi" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="#eda712" /> + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..810a095 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..534341c Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..d4801a8 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-hdpi/icon.png b/app/src/main/res/mipmap-hdpi/icon.png deleted file mode 100644 index 960a148..0000000 Binary files a/app/src/main/res/mipmap-hdpi/icon.png and /dev/null differ diff --git a/app/src/main/res/mipmap-ldpi/icon.png b/app/src/main/res/mipmap-ldpi/icon.png deleted file mode 100644 index 494c897..0000000 Binary files a/app/src/main/res/mipmap-ldpi/icon.png and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..d80f36b Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..f907330 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..60e8276 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/icon.png b/app/src/main/res/mipmap-mdpi/icon.png deleted file mode 100644 index adf62b8..0000000 Binary files a/app/src/main/res/mipmap-mdpi/icon.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..eb57116 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..0d67d2e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..8883f45 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/icon.png b/app/src/main/res/mipmap-xhdpi/icon.png deleted file mode 100644 index b51271b..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/icon.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..0d301e8 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..bdcd09f Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..4d28019 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..8ccb5db Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..4ca7614 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..62540c4 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values-v11/themes.xml b/app/src/main/res/values-v11/themes.xml deleted file mode 100644 index 3b567a6..0000000 --- a/app/src/main/res/values-v11/themes.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - -