diff --git a/.github/workflows/app-build.yaml b/.github/workflows/app-build.yaml new file mode 100644 index 0000000..8702243 --- /dev/null +++ b/.github/workflows/app-build.yaml @@ -0,0 +1,36 @@ +name: App / Build + +on: + push: + branches: + - master + pull_request: + +permissions: + contents: read + +jobs: + build: + name: Build + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Java + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0 + with: + distribution: temurin + java-version: 17 + - name: Setup Gradle + uses: gradle/gradle-build-action@ef76a971e2fa3f867b617efd72f2fbd72cf6f8bc # v2.8.0 + - name: Assemble debug APKs + run: ./gradlew assembleDebug + - name: Create publish bundle + run: mkdir -p build/gh-app-publish/; find app/build/ -iname "*.apk" -exec mv "{}" build/gh-app-publish/ \; + - name: Upload artifacts + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + with: + name: build-artifacts + retention-days: 14 + if-no-files-found: error + path: build/gh-app-publish/ \ No newline at end of file diff --git a/.github/workflows/app-lint.yaml b/.github/workflows/app-lint.yaml new file mode 100644 index 0000000..1d45ef2 --- /dev/null +++ b/.github/workflows/app-lint.yaml @@ -0,0 +1,38 @@ +name: App / Lint + +on: + push: + branches: + - master + - release-* + pull_request: + +permissions: + contents: read + security-events: write + +jobs: + lint: + name: Lint + runs-on: ubuntu-22.04 + continue-on-error: true + strategy: + matrix: + task: [ lint ] + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Java + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 + with: + distribution: temurin + java-version: 17 + - name: Setup Gradle + uses: gradle/gradle-build-action@87a9a15658c426a54dd469d4fc7dc1a73ca9d4a6 # v2.10.0 + - name: Run ${{ matrix.task }} task + run: ./gradlew ${{ matrix.task }} + - name: Upload SARIF files + uses: github/codeql-action/upload-sarif@c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2 # v2.22.9 + if: ${{ always() }} + with: + sarif_file: . \ No newline at end of file diff --git a/.github/workflows/app-test.yaml b/.github/workflows/app-test.yaml new file mode 100644 index 0000000..dbb29a5 --- /dev/null +++ b/.github/workflows/app-test.yaml @@ -0,0 +1,28 @@ +name: APP / Test + +on: + push: + branches: + - master + pull_request: + +jobs: + test: + name: Test + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + java: [ 17 ] + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Java + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0 + with: + distribution: temurin + java-version: ${{ matrix.java }} + - name: Setup Gradle + uses: gradle/gradle-build-action@87a9a15658c426a54dd469d4fc7dc1a73ca9d4a6 # v2.10.0 + - name: Run test task + run: ./gradlew test diff --git a/.github/workflows/gradlew-validate.yaml b/.github/workflows/gradlew-validate.yaml new file mode 100644 index 0000000..044b238 --- /dev/null +++ b/.github/workflows/gradlew-validate.yaml @@ -0,0 +1,22 @@ +name: Gradle / Validate wrapper + +on: + push: + branches: + - master + pull_request: + paths: + - '**/gradlе-wrapper.jar' + +permissions: + contents: read + +jobs: + validate: + name: Validate + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Validate Gradle Wrapper + uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # v1.1.0 \ No newline at end of file diff --git a/apklis-api/build.gradle.kts b/apklis-api/build.gradle.kts index 64f078d..ca585db 100644 --- a/apklis-api/build.gradle.kts +++ b/apklis-api/build.gradle.kts @@ -20,6 +20,12 @@ android { targetCompatibility = JavaVersion.VERSION_17 } + lint { + lintConfig = file("$rootDir/android-lint.xml") + abortOnError = false + sarifReport = true + } + buildTypes { release { isMinifyEnabled = false @@ -38,7 +44,7 @@ dependencies { implementation("androidx.constraintlayout:constraintlayout:2.1.4") - implementation("com.google.android.material:material:1.9.0") + implementation("com.google.android.material:material:1.11.0") implementation("androidx.appcompat:appcompat:1.6.1") implementation("io.reactivex.rxjava2:rxjava:2.2.19") @@ -46,11 +52,12 @@ dependencies { implementation("io.reactivex.rxjava2:rxandroid:2.1.1") implementation("com.squareup.retrofit2:adapter-rxjava2:2.8.1") - implementation("com.squareup.okhttp3:okhttp:4.5.0") - implementation("com.squareup.retrofit2:retrofit:2.8.1") - implementation("com.squareup.retrofit2:converter-gson:2.8.1") + implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") testImplementation("junit:junit:4.13.2") + testImplementation("com.squareup.okhttp3:mockwebserver:4.9.1") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") diff --git a/apklis-api/src/main/java/com/arr/apklislib/payments/ApklisPay.java b/apklis-api/src/main/java/com/arr/apklislib/payments/ApklisPay.java index 32406df..4e75005 100644 --- a/apklis-api/src/main/java/com/arr/apklislib/payments/ApklisPay.java +++ b/apklis-api/src/main/java/com/arr/apklislib/payments/ApklisPay.java @@ -5,15 +5,16 @@ import android.database.Cursor; import android.net.Uri; import android.os.Build; +import android.util.Log; public class ApklisPay { + private static final String TAG = "ApklisPay"; + private static final String APKLIS_URL = "content://cu.uci.android.apklis.payment.provider/app/"; + private static final String APK_PAID = "paid"; + private static final String USER = "user_name"; - private String APKLIS_URL = "content://cu.uci.android.apklis.payment.provider/app/"; - private String APK_PAID = "paid"; - private String USER = "user_name"; - - private Context mContext; - private String packageName; + private final Context mContext; + private final String packageName; private boolean isPaid = false; private String usuario = null; @@ -34,8 +35,10 @@ private void checkPayment() { Cursor cursor = content.query(provider, null, null, null, null); if (cursor != null) { if (cursor.moveToFirst()) { - isPaid = cursor.getInt(cursor.getColumnIndex(APK_PAID)) > 0; - usuario = cursor.getString(cursor.getColumnIndex(USER)); + int paidColumnIndex = cursor.getColumnIndex(APK_PAID); + int userColumnIndex = cursor.getColumnIndex(USER); + isPaid = cursor.getInt(paidColumnIndex) > 0; + usuario = cursor.getString(userColumnIndex); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { content.close(); @@ -46,7 +49,8 @@ private void checkPayment() { } } } catch (Exception e) { - e.printStackTrace(); + Log.e(TAG, "checkPayment: Fail", e); + ; } finally { if (content != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { content.release(); diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/APKLisService.java b/apklis-api/src/main/java/com/arr/apklislib/update/APKLisService.java new file mode 100644 index 0000000..41307db --- /dev/null +++ b/apklis-api/src/main/java/com/arr/apklislib/update/APKLisService.java @@ -0,0 +1,14 @@ +package com.arr.apklislib.update; + +import com.arr.apklislib.update.model.PackageResponse; + +import io.reactivex.Single; +import retrofit2.http.GET; +import retrofit2.http.Headers; +import retrofit2.http.Query; + +public interface APKLisService { + @Headers({"User-Agent: ApplifyCU/1.0.0", "Content-Type: application/json"}) + @GET("/application/") + public Single getPackageResponse(@Query("package_name") String packageName); +} diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/ApklisException.java b/apklis-api/src/main/java/com/arr/apklislib/update/ApklisException.java new file mode 100644 index 0000000..8c0ebce --- /dev/null +++ b/apklis-api/src/main/java/com/arr/apklislib/update/ApklisException.java @@ -0,0 +1,7 @@ +package com.arr.apklislib.update; + +public class ApklisException extends Exception { + public ApklisException(String message) { + super(message); + } +} diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/ApklisUpdate.java b/apklis-api/src/main/java/com/arr/apklislib/update/ApklisUpdate.java index 198965e..34f5793 100644 --- a/apklis-api/src/main/java/com/arr/apklislib/update/ApklisUpdate.java +++ b/apklis-api/src/main/java/com/arr/apklislib/update/ApklisUpdate.java @@ -2,94 +2,92 @@ import android.content.Context; import android.content.pm.PackageManager; -import android.os.Handler; -import android.os.Looper; import android.util.Log; +import androidx.annotation.NonNull; + import com.arr.apklislib.update.callback.UpdateCallback; -import com.arr.apklislib.update.model.ApiResponse; import com.arr.apklislib.update.model.LastRelease; -import com.arr.apklislib.update.model.UpdateInfo; -import com.google.gson.Gson; - -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import java.io.IOException; -import java.util.List; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; public class ApklisUpdate { + private static final String TAG = "ApklisUpdate"; + private final APKLisService service; - private static final String API_URL = "https://api.apklis.cu/v1/application/?package_name="; - private Context context; - private OkHttpClient httpClient; - private Gson gson; - private Handler handler; - - public ApklisUpdate(Context context) { - this.context = context; - httpClient = new OkHttpClient(); - gson = new Gson(); - handler = new Handler(Looper.getMainLooper()); + ApklisUpdate(APKLisService service) { + this.service = service; } public void checkLastUpdate(String package_name, final UpdateCallback callback) { - Request request = new Request.Builder().url(API_URL + package_name).build(); - httpClient - .newCall(request) - .enqueue( - new Callback() { - @Override - public void onResponse(Call call, Response response) - throws IOException { - if (response.isSuccessful()) { - String result = response.body().string(); - Log.e("Result: ", "" + result.toString()); - - // - ApiResponse api = gson.fromJson(result, ApiResponse.class); - List info = api.appUpdateInfo(); - - if (info != null && !info.isEmpty()) { - UpdateInfo updateInfo = info.get(0); - LastRelease release = updateInfo.lastRelease(); - - // compribar las version code - int serverVersionCode = release.versionCode(); - int appVersionCode = getCurrentVersionCode(); - if (serverVersionCode > appVersionCode) { - handler.post(() -> callback.onLastUpdate(release)); - } - } - - } else { - handler.post( - () -> - callback.onError( - new Exception( - "Error occurred during network request"))); - } - } + service.getPackageResponse(package_name) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(response -> { + if (response.getCount() == 0) { + callback.onError(new ApklisException("No existen apps publicadas con este nombre de paquete en apklis")); + } else { + callback.onLastUpdate(response.getResults().get(0).getLastRelease()); + } + }, throwable -> { + callback.onError((Exception) throwable); + }).dispose(); + } - @Override - public void onFailure(Call call, IOException e) { - callback.onError(e); - } - }); + public void hasAppUpdate(@NonNull Context context, UpdateCallback callback) { + service.getPackageResponse(context.getPackageName()) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(response -> { + if (response.getCount() == 0) { + callback.onError(new ApklisException("No existen apps publicadas con este nombre de paquete en apklis")); + } else { + LastRelease lastRelease = response.getResults().get(0).getLastRelease(); + if (getCurrentVersionCode(context) < lastRelease.getVersionCode()) { + callback.onLastUpdate(lastRelease); + } + } + }, throwable -> { + callback.onError((Exception) throwable); + }).dispose(); } - private int getCurrentVersionCode() { + private int getCurrentVersionCode(@NonNull Context context) { // Obtener el versionCode actual de la aplicación try { return context.getPackageManager() .getPackageInfo(context.getPackageName(), 0) .versionCode; } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); + Log.e(TAG, "getCurrentVersionCode: " + e.getMessage(), e); + ; } return 0; } + + public static class Builder { + private APKLisService service; + + public Builder setService(APKLisService service) { + this.service = service; + return this; + } + + public ApklisUpdate build() { + if (service == null) { + String API_URL = "https://api.apklis.cu/v2"; + service = new Retrofit.Builder() + .baseUrl(API_URL) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .build() + .create(APKLisService.class); + } + return new ApklisUpdate(service); + } + } } diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/model/ABI.java b/apklis-api/src/main/java/com/arr/apklislib/update/model/ABI.java new file mode 100644 index 0000000..ba28915 --- /dev/null +++ b/apklis-api/src/main/java/com/arr/apklislib/update/model/ABI.java @@ -0,0 +1,10 @@ +package com.arr.apklislib.update.model; + +import com.google.gson.annotations.SerializedName; + +public class ABI { + @SerializedName("abi") + private String abi; + + public String getABI() { return abi; } +} diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/model/ApiResponse.java b/apklis-api/src/main/java/com/arr/apklislib/update/model/ApiResponse.java deleted file mode 100644 index aa40b30..0000000 --- a/apklis-api/src/main/java/com/arr/apklislib/update/model/ApiResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.arr.apklislib.update.model; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class ApiResponse { - - @SerializedName("results") - private List updateInfo; - - public List appUpdateInfo() { - return updateInfo; - } -} diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/model/LastRelease.java b/apklis-api/src/main/java/com/arr/apklislib/update/model/LastRelease.java index 23e8f78..8c34014 100644 --- a/apklis-api/src/main/java/com/arr/apklislib/update/model/LastRelease.java +++ b/apklis-api/src/main/java/com/arr/apklislib/update/model/LastRelease.java @@ -2,47 +2,95 @@ import com.google.gson.annotations.SerializedName; -public class LastRelease { +import java.util.List; +public class LastRelease { + @SerializedName("abi") + private List abi; + @SerializedName("app_name") + private String appName; + @SerializedName("beta") + private boolean beta; + @SerializedName("changelog") + private String changelog; + @SerializedName("deleted") + private boolean deleted; + @SerializedName("developer") + private String developer; + @SerializedName("icon") + private String icon; + @SerializedName("id") + private long id; + @SerializedName("no_abi") + private boolean noABI; + @SerializedName("package_name") + private String packageName; + @SerializedName("permissions") + private List permissions; + @SerializedName("public") + private boolean isPublic; + @SerializedName("published") + private String published; + @SerializedName("screenshots") + private List screenshots; + @SerializedName("sha256") + private String sha256; + @SerializedName("size") + private String size; @SerializedName("version_code") - private int versionCode; - + private long versionCode; @SerializedName("version_name") private String versionName; + @SerializedName("version_sdk") + private String versionSDK; + @SerializedName("version_sdk_name") + private String versionSDKName; + @SerializedName("version_target_sdk") + private long versionTargetSDK; + @SerializedName("version_target_sdk_name") + private long versionTargetSDKName; - @SerializedName("published") - private String datePublished; + public List getABI() { return abi; } - @SerializedName("changelog") - private String changelog; + public String getAppName() { return appName; } - @SerializedName("size") - private int size; + public boolean getBeta() { return beta; } - @SerializedName("icon") - private String icon; + public String getChangelog() { return changelog; } + + public boolean getDeleted() { return deleted; } + + public String getDeveloper() { return developer; } + + public String getIcon() { return icon; } + + public long getID() { return id; } + + public boolean getNoABI() { return noABI; } + + public String getPackageName() { return packageName; } + + public List getPermissions() { return permissions; } + + public boolean getPublic() { return isPublic; } + + public String getPublished() { return published; } + + public List getScreenshots() { return screenshots; } + + public String getSha256() { return sha256; } + + public String getSize() { return size; } - public int versionCode() { - return versionCode; - } + public long getVersionCode() { return versionCode; } - public String versionName() { - return versionName; - } + public String getVersionName() { return versionName; } - public String datePublished() { - return datePublished; - } + public String getVersionSDK() { return versionSDK; } - public String appChangelog() { - return changelog; - } + public String getVersionSDKName() { return versionSDKName; } - public int appSize() { - return size; - } + public long getVersionTargetSDK() { return versionTargetSDK; } - public String appIcon() { - return icon; - } + public long getVersionTargetSDKName() { return versionTargetSDKName; } } diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/model/PackageResponse.java b/apklis-api/src/main/java/com/arr/apklislib/update/model/PackageResponse.java new file mode 100644 index 0000000..21441a5 --- /dev/null +++ b/apklis-api/src/main/java/com/arr/apklislib/update/model/PackageResponse.java @@ -0,0 +1,17 @@ +package com.arr.apklislib.update.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; +import java.util.Map; + +public class PackageResponse { + @SerializedName("count") + private long count; + @SerializedName("results") + private List results; + + public long getCount() { return count; } + + public List getResults() { return results; } +} diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/model/Permission.java b/apklis-api/src/main/java/com/arr/apklislib/update/model/Permission.java new file mode 100644 index 0000000..0a1d102 --- /dev/null +++ b/apklis-api/src/main/java/com/arr/apklislib/update/model/Permission.java @@ -0,0 +1,18 @@ +package com.arr.apklislib.update.model; + +import com.google.gson.annotations.SerializedName; + +public class Permission { + @SerializedName("description") + private String description; + @SerializedName("icon") + private String icon; + @SerializedName("name") + private String name; + + public String getDescription() { return description; } + + public String getIcon() { return icon; } + + public String getName() { return name; } +} diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/model/UpdateInfo.java b/apklis-api/src/main/java/com/arr/apklislib/update/model/Result.java similarity index 59% rename from apklis-api/src/main/java/com/arr/apklislib/update/model/UpdateInfo.java rename to apklis-api/src/main/java/com/arr/apklislib/update/model/Result.java index 0668bf3..466aaad 100644 --- a/apklis-api/src/main/java/com/arr/apklislib/update/model/UpdateInfo.java +++ b/apklis-api/src/main/java/com/arr/apklislib/update/model/Result.java @@ -1,13 +1,10 @@ package com.arr.apklislib.update.model; + import com.google.gson.annotations.SerializedName; -public class UpdateInfo { - +public class Result { @SerializedName("last_release") private LastRelease lastRelease; - - - public LastRelease lastRelease(){ - return lastRelease; - } + + public LastRelease getLastRelease() { return lastRelease; } } diff --git a/apklis-api/src/main/java/com/arr/apklislib/update/model/Screenshot.java b/apklis-api/src/main/java/com/arr/apklislib/update/model/Screenshot.java new file mode 100644 index 0000000..d197c16 --- /dev/null +++ b/apklis-api/src/main/java/com/arr/apklislib/update/model/Screenshot.java @@ -0,0 +1,18 @@ +package com.arr.apklislib.update.model; + +import com.google.gson.annotations.SerializedName; + +public class Screenshot { + @SerializedName("description") + private String description; + @SerializedName("id") + private long id; + @SerializedName("img") + private String img; + + public String getDescription() { return description; } + + public long getID() { return id; } + + public String getImg() { return img; } +} diff --git a/apklis-api/src/test/java/com/arr/apklislib/update/APKLisServiceTest.java b/apklis-api/src/test/java/com/arr/apklislib/update/APKLisServiceTest.java new file mode 100644 index 0000000..6e059c3 --- /dev/null +++ b/apklis-api/src/test/java/com/arr/apklislib/update/APKLisServiceTest.java @@ -0,0 +1,99 @@ +package com.arr.apklislib.update; + + +import com.arr.apklislib.update.model.PackageResponse; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import okio.BufferedSource; +import okio.Okio; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +@RunWith(JUnit4.class) +public class APKLisServiceTest { + private MockWebServer mockWebServer; + private APKLisService service; + + @Before + public void setUp() throws IOException { + mockWebServer = new MockWebServer(); + mockWebServer.start(); + + service = new Retrofit.Builder() + .baseUrl(mockWebServer.url("/")) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .build().create(APKLisService.class); + } + + @After + public void tearDown() throws Exception { + mockWebServer.shutdown(); + } + + @Test + public void getPackageResponseOk() throws Exception { + enqueueResponse("package_response_ok.json"); + + PackageResponse data = service.getPackageResponse("com.arr.example").blockingGet(); + RecordedRequest request = mockWebServer.takeRequest(); + + Assert.assertEquals(request.getMethod(), "GET"); + Assert.assertEquals(request.getPath(), "/application/?package_name=com.arr.example"); + Assert.assertEquals(request.getHeader("User-Agent"), "ApplifyCU/1.0.0"); + Assert.assertEquals(request.getHeader("Content-Type"), "application/json"); + + Assert.assertEquals(data.getCount(), 1); + Assert.assertEquals(data.getResults().get(0).getLastRelease().getVersionName(), "v5.0-beta"); + Assert.assertEquals(data.getResults().get(0).getLastRelease().getAppName(), "SIMple"); + Assert.assertEquals(data.getResults().get(0).getLastRelease().getVersionCode(), 50); + Assert.assertEquals(data.getResults().get(0).getLastRelease().getSize(), "9.99 MB"); + Assert.assertEquals(data.getResults().get(0).getLastRelease().getID(), 62604); + } + + @Test + public void getPackageResponseNotFound() throws Exception { + enqueueResponse("package_response_empty.json"); + + PackageResponse data = service.getPackageResponse("com.arr.example").blockingGet(); + RecordedRequest request = mockWebServer.takeRequest(); + + Assert.assertEquals(request.getMethod(), "GET"); + Assert.assertEquals(request.getPath(), "/application/?package_name=com.arr.example"); + Assert.assertEquals(request.getHeader("User-Agent"), "ApplifyCU/1.0.0"); + Assert.assertEquals(request.getHeader("Content-Type"), "application/json"); + + Assert.assertEquals(data.getCount(), 0); + Assert.assertEquals(data.getResults().size(), 0); + } + + private void enqueueResponse(String fileName) throws IOException { + + InputStream inputStream = Objects.requireNonNull(getClass().getClassLoader()).getResourceAsStream("api-response/" + fileName); + + assert inputStream != null; + BufferedSource source = Okio.buffer(Okio.source(inputStream)); + + String body = source.readString(StandardCharsets.UTF_8); + + MockResponse mockResponse = new MockResponse() + .setBody(body); + + mockWebServer.enqueue(mockResponse); + } +} \ No newline at end of file diff --git a/apklis-api/src/test/resources/api-response/package_response_empty.json b/apklis-api/src/test/resources/api-response/package_response_empty.json new file mode 100644 index 0000000..04e070e --- /dev/null +++ b/apklis-api/src/test/resources/api-response/package_response_empty.json @@ -0,0 +1,7 @@ +{ + "count": 0, + "next": null, + "previous": null, + "facets": {}, + "results": [] +} \ No newline at end of file diff --git a/apklis-api/src/test/resources/api-response/package_response_ok.json b/apklis-api/src/test/resources/api-response/package_response_ok.json new file mode 100644 index 0000000..504feaa --- /dev/null +++ b/apklis-api/src/test/resources/api-response/package_response_ok.json @@ -0,0 +1,225 @@ +{ + "count": 1, + "next": null, + "previous": null, + "facets": {}, + "results": [ + { + "icon": "https://archive.apklis.cu/application/icon/com.arr.simple-v50.png", + "background": "", + "package_name": "com.arr.simple", + "name": "SIMple", + "video_url": "", + "video_img": "", + "description": "

SIMple es una aplicación altamente funcional y versátil diseñada para simplificar y optimizar la gestión de paquetes de datos, llamadas y conexiones a redes WiFi y Nauta Hogar. Con una interfaz intuitiva y amigable, SIMple ofrece una amplia gama de características y funcionalidades que permiten a los usuarios tener un control completo sobre sus servicios de comunicación.

CONTACTO

Telegram

Twitter

", + "updated": "2024-01-19T04:09:06.324050+00:00", + "sale_count": 0, + "download_count": 3196, + "price": 0.0, + "rating": 4.2, + "sponsored": 0, + "with_db": false, + "reviews_star_1": 1, + "reviews_star_2": 0, + "reviews_star_3": 1, + "reviews_star_4": 2, + "reviews_star_5": 6, + "releases_count": 5, + "reviews_count": 10, + "categories": [ + { + "name": "Cuba", + "icon": "cubans", + "group": "Applications", + "icon_url": "https://archive.apklis.cu/category/Aplicaciones_y_juegos_cubanos.png" + }, + { + "name": "Utilidades", + "icon": "utils", + "group": "Applications", + "icon_url": "https://archive.apklis.cu/category/Utilidades_b48JMjB.png" + }, + { + "name": "Herramientas", + "icon": "tools", + "group": "Applications", + "icon_url": "https://archive.apklis.cu/category/Herramientas_y_utilidades_nUE9z86.png" + }, + { + "name": "Estilo de vida", + "icon": "lifestyle", + "group": "Applications", + "icon_url": "https://archive.apklis.cu/category/EstiloDeVida.png" + } + ], + "size": 10475495, + "last_release": { + "developer": "alessandro", + "no_abi": true, + "version_name": "v5.0-beta", + "package_name": "com.arr.simple", + "app_name": "SIMple", + "version_sdk_name": "Marshmallow 6.0 - 6.0.1", + "version_target_sdk_name": 34, + "permissions": [ + { + "icon": "", + "description": "", + "name": "Access network state" + }, + { + "icon": "", + "description": "", + "name": "Call phone" + }, + { + "icon": "", + "description": "", + "name": "Camera" + }, + { + "icon": "", + "description": "", + "name": "Change network state" + }, + { + "icon": "", + "description": "", + "name": "Foreground service" + }, + { + "icon": "", + "description": "", + "name": "Foreground service connected device" + }, + { + "icon": "", + "description": "", + "name": "Internet" + }, + { + "icon": "", + "description": "", + "name": "Post notifications" + }, + { + "icon": "", + "description": "", + "name": "Read calendar" + }, + { + "icon": "", + "description": "", + "name": "Read contacts" + }, + { + "icon": "", + "description": "", + "name": "Read external storage" + }, + { + "icon": "", + "description": "", + "name": "Read phone numbers" + }, + { + "icon": "", + "description": "", + "name": "Read phone state" + }, + { + "icon": "", + "description": "", + "name": "Receive boot completed" + }, + { + "icon": "", + "description": "", + "name": "Schedule exact alarm" + }, + { + "icon": "", + "description": "", + "name": "System alert window" + }, + { + "icon": "", + "description": "", + "name": "Use biometric" + }, + { + "icon": "", + "description": "", + "name": "Use exact alarm" + }, + { + "icon": "", + "description": "", + "name": "Use fingerprint" + }, + { + "icon": "", + "description": "", + "name": "Wake lock" + }, + { + "icon": "", + "description": "", + "name": "Write calendar" + }, + { + "icon": "", + "description": "", + "name": "Write external storage" + }, + { + "icon": "", + "description": "", + "name": "Dynamic receiver not exported permission" + } + ], + "screenshots": [ + { + "description": "", + "img": "https://archive.apklis.cu/application/screenshot/unnamed.webp", + "id": 442828 + }, + { + "description": "", + "img": "https://archive.apklis.cu/application/screenshot/unnamed_1_1Oi4VuV.webp", + "id": 442829 + }, + { + "description": "", + "img": "https://archive.apklis.cu/application/screenshot/unnamed_2_EpoG7cf.webp", + "id": 442830 + }, + { + "description": "", + "img": "https://archive.apklis.cu/application/screenshot/unnamed_3_V36Yywx.webp", + "id": 442831 + } + ], + "deleted": false, + "id": 62604, + "changelog": "
  •  Corrección de errores con la burbuja flotante en Android 14
  • Se agrega la posibilidad de cerrar la burbuja flotante sin tener que ir a los Ajustes. Déjela presionada para cerrarla hasta que vuelva a inicializar la app.
", + "version_code": 50, + "published": "2024-01-19T04:09:06.324050Z", + "sha256": "fe33e02eb92134028fc802b4e3f387dbc5a9bb0917965f20e866a52b345d0cac", + "size": "9.99 MB", + "icon": "https://archive.apklis.cu/application/icon/com.arr.simple-v50.png", + "public": true, + "beta": false, + "version_sdk": "Marshmallow 6.0 - 6.0.1", + "version_target_sdk": 34 + }, + "developer": { + "username": "alessandro", + "full_name": "Alessandro Rodríguez", + "first_name": "Alessandro Rodríguez", + "last_name": "" + }, + "announced": false + } + ] +} \ No newline at end of file diff --git a/app/src/main/java/com/arr/example/MainActivity.java b/app/src/main/java/com/arr/example/MainActivity.java index eb0c121..897fd58 100644 --- a/app/src/main/java/com/arr/example/MainActivity.java +++ b/app/src/main/java/com/arr/example/MainActivity.java @@ -28,16 +28,16 @@ protected void onCreate(Bundle savedInstanceState) { // set content view to binding's root setContentView(binding.getRoot()); - ApklisUpdate api = new ApklisUpdate(this); - api.checkLastUpdate( - this.getPackageName(), + ApklisUpdate api = new ApklisUpdate.Builder().build(); + api.hasAppUpdate( + this, new UpdateCallback() { @Override public void onLastUpdate(LastRelease info) { - Spanned changelog = formatHtmlString(info.appChangelog()); + Spanned changelog = formatHtmlString(info.getChangelog()); new ApklisUpdateDialog(MainActivity.this) .setTitle("Nueva Versión") - .setVersion(info.versionName()) + .setVersion(info.getVersionName()) .setChangelog(changelog.toString()) .show(); } diff --git a/gradlew b/gradlew old mode 100644 new mode 100755