diff --git a/.gitignore b/.gitignore index 10e6232230b8af64e1cdc41f3c12566ae8298864..69cdb756e11ee913469bf71e50f2b1540e1ef201 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,8 @@ gradle-app.setting /request.* /local.properties /src/main/java/com/aurora/gplayapi/tests/* +/lib/src/test/java/com/aurora/gplayapi/* okhttp_cache/ + +# MAC OSX system files +*.DS_Store diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bb7432004157d7725d3dd3e28d35257ea9acfb9d..ec819a471cc85f2c8ab2d89ef61e4cc43ad8c42f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,17 +4,21 @@ stages: - build - deploy +before_script: +- export GRADLE_USER_HOME=$(pwd)/.gradle +- chmod +x ./gradlew + build-job: stage: build script: - - gradle build + - ./gradlew publishReleasePublicationToLocalRepository artifacts: paths: - - build/libs + - lib/build/repo/foundation/e/gplayapi deploy: stage: deploy script: - - gradle publish + - ./gradlew publishReleasePublicationToGitLabRepository only: - master diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000000000000000000000000000000000000..ddc3ee5db195107e9c8d8e7d2d4d72d12f2bb0e4 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,67 @@ +Changelog : v3.2.10 +• Switch from Fuel to OkHttp library for network calls +• Update dependencies & plugins +• Bump compileSdk to 34 + +Changelog : v3.2.9 +• Fix PurchaseHelper while purchasing apps with certificate hash + +Changelog : v3.2.8 +• Publish GPlayAPI on GitLab Package Registry + +Changelog : v3.2.7 +• Provide SHA256 and/or SHA1 when available for files purchased using PurchaseHelper + +Changelog : v3.2.6 +• Introduce new getDetailsResponseByPackageName method +• Define more possible restrictions +• Handle default for OTA property +• Add compatibility information for active device +• Expose required android version (or minSdk) for apps in app info + +Changelog : v3.2.5 +• Minor fix to PurchaseHelper to handle duplicates + +Changelog : v3.2.4 +• Improve WebSearchHelper +• Fix non-ASCII characters issues in search suggestions & query + +Changelog : v3.2.3 +• Boring release + +Changelog : v3.2.2 +• Improve AuthValidator +• Do not generate unused ac2dm & gcm tokens + +Changelog : v3.2.1 +• Fix WebSearchHelper + +Changelog : v3.2.0 +• Initial Web APIs support for search suggestions and results +• Migrate to Kotlin DSL for gradle files +• Add a sample app for easier testing and fixes + +Changelog : v3.1.4 +• Add Google Pixel Tablet spoofing configuration +• Bump minimum compile SDK to API 21 +• Enable and compile with java language 17 features +• Make App class parcelable + +Changelog : v3.1.3 +• Implement shared library dependencies API + +Changelog : v3.1.2 +• Fix lint issue with getting authentication value from HashMap +• Create a jitpack configuration for JDK 17 support + +Changelog : v3.1.1 +• Added Google Pixel 7a, Xiaomi 11 Lite 5G NE and Sony Bravia VU2 spoofing configurations +• Copied proguard rule from Aurora Store +• Updated dependencies and docker image + +Changelog : v3.1.0 +• Exposed response code for network calls via StateFlow from IHttpClient interface +• Keep device properties from being shrinked + +Changelog : v3.0.1 +• Initial changes (migration to AAR) diff --git a/README.md b/README.md index 1314fc0b32a4acffaa8d01344348ba5b06441b32..08c930374b003de992e2e85b28935370a840893e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Google Play Store Protobuf API wrapper in Kotlin -**For Educational & Research purpose only +**For Educational & Research purpose only** ## Disclaimer @@ -13,78 +13,128 @@ I'm not resposible for anything that may go wrong with: 4. Girlfriend. 5. Crypto Wallet. -***Hold your own beer! +**Hold your own beer!** + +## Download + +GPlayAPI is available on [GitLab Package Registry](https://gitlab.com/AuroraOSS/gplayapi/-/packages). + +Add the maven repository into `settings.gradle.kts` file's repository block: + +```kotlin +maven("https://gitlab.com/api/v4/projects/18497829/packages/maven") +``` + +Then, add a dependency upon the library in the `build.gradle.kts` file's dependency block: + +```kotlin +implementation("com.aurora:gplayapi:3.2.10") +``` ## Build - git clone https://gitlab.com/AuroraOSS/gplayapi.git - gradlew :assemble - gradlew :build +To build the library locally, run the following commands: + +```shell +git clone https://gitlab.com/AuroraOSS/gplayapi.git && cd gplayapi +./gradlew publishReleasePublicationToLocalRepository +``` + +This will generate an unsigned release build +([AAR](https://developer.android.com/studio/projects/android-library.html#aar-contents)) in the +`lib/build/repo` directory. ## Work Flow - 1. Obtain AASToken from (Email,Password) pair. - 2. Obtain AuthData from (Email,AASToken) pair. - 3. Use AuthData to access data. -## Usage +1. Obtain AASToken from (Email, Password) pair. +2. Obtain AuthData from (Email, AASToken) pair. +3. Use AuthData to access data. + ### AASToken Use one of the following tools * [Authenticator](https://github.com/whyorean/Authenticator) * [AASTokenGrabber](https://github.com/whyorean/AASTokenGrabber) +## Usage + +You need to build an instance of `AuthData` to call any method related with the API. Building an +instance requires Email and AASToken fetched from the above-mentioned workflow. + ### AuthData - val authData = AuthHelper.build(email,aastoken) +```kotlin +val authData = AuthHelper.build(email, aastoken) +``` ### Fetch App Details - val app = AppDetailsHelper(authData).getAppByPackageName(packageName) +```kotlin +val app = AppDetailsHelper(authData).getAppByPackageName(packageName) +``` ### Fetch Bulk App Details - val appList = AppDetailsHelper.getAppByPackageName(packageNameList) +```kotlin +val appList = AppDetailsHelper.getAppByPackageName(packageNameList) +``` ### Fetch APKs/OBBs/Patches - val files = PurchaseHelper(authData).purchase( - app.packageName, - app.versionCode, - app.offerType - ) +```kotlin +val files = PurchaseHelper(authData).purchase( + app.packageName, + app.versionCode, + app.offerType +) +``` ### Fetch All Categories - val categoryList = CategoryHelper(authData).getAllCategoriesList(type) //type = GAME or APPLICATION +```kotlin +val categoryList = CategoryHelper(authData).getAllCategoriesList(type) //type = GAME or APPLICATION +``` ### Fetch Search Suggestions - val entries = SearchHelper(authData).searchSuggestions(query) +```kotlin +val entries = SearchHelper(authData).searchSuggestions(query) +``` ### Search Apps & Games - var helper = SearchHelper(authData) - var searchBundle = helper.searchResults(query) - var appList = searchBundle.appList - - #To fetch next list - appList = helper.next(searchBundle.subBundles) +```kotlin +var helper = SearchHelper(authData) +var searchBundle = helper.searchResults(query) +var appList = searchBundle.appList + +// To fetch next list +appList = helper.next(searchBundle.subBundles) +``` ### App Reviews - var helper = ReviewsHelper(authData) - var reviewCluster = helper.getReviews(packageName, filter) //filter = ALL, POSITIVE, CRITICAL - #To fetch next list - reviewCluster = helper.next(reviewCluster.nextPageUrl) +```kotlin +var helper = ReviewsHelper(authData) +var reviewCluster = helper.getReviews(packageName, filter) //filter = ALL, POSITIVE, CRITICAL + +// To fetch next list +reviewCluster = helper.next(reviewCluster.nextPageUrl) +``` ### User Reviews - var helper = ReviewsHelper(authData) - //Submit or Edit review - val review = helper.addOrEditReview(packageName, title, content, rating, isBeta) - //Retrive review - val review = helper.getUserReview(packageName, isBeta) +```kotlin +var helper = ReviewsHelper(authData) + +//Submit or Edit review +val review = helper.addOrEditReview(packageName, title, content, rating, isBeta) + +//Retrive review +val review = helper.getUserReview(packageName, isBeta) +``` ## Credits + 1. [googleplay-api](https://github.com/egirault/googleplay-api) 2. [google-play-crawler](https://github.com/Akdeniz/google-play-crawler) 3. [play-store-api](https://github.com/yeriomin/play-store-api) diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 6f6083169aaf32b475dad04a5274967da709a53b..0000000000000000000000000000000000000000 --- a/build.gradle +++ /dev/null @@ -1,124 +0,0 @@ -/* - * GPlayApi - * Copyright (C) 2020 Aurora OSS - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -buildscript { - repositories { - jcenter() - } - dependencies { - classpath("com.google.protobuf:protobuf-gradle-plugin:0.8.12") - } -} - -plugins { - id("java-library") - id("com.google.protobuf") version("0.8.12") - id("org.jetbrains.kotlin.jvm") version("1.4.10") - id("maven-publish") -} - -group("com.aurora") -version("3.0.1-2") - -repositories { - mavenCentral() -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - - //Protobuf - implementation "com.google.protobuf:protobuf-java:3.10.0" - - //Fuel - implementation("com.github.kittinunf.fuel:fuel:2.3.0") - - //Gson - implementation 'com.google.code.gson:gson:2.8.6' -} - -sourceSets { - main.kotlin.srcDirs += "src/main/java" - main.kotlin.srcDirs += "build/generated/source/proto/main/java" -} - -tasks.withType(JavaCompile) { - options.encoding = ("UTF-8") -} - -jar { - exclude("*.proto") -} - -clean { - delete protobuf.generatedFilesBaseDir -} - -protobuf { - protoc { - artifact = ("com.google.protobuf:protoc:3.10.0") - } -} - -publishing { - publications { - maven(MavenPublication) { - groupId 'foundation.e' - artifactId 'gplayapi' - version version - artifact "$buildDir/libs/gplayapi-${version}.jar" - - //generate pom nodes for dependencies - pom.withXml { - def dependenciesNode = asNode().appendNode('dependencies') - configurations.implementation.allDependencies.each { dependency -> - if (dependency.name != 'unspecified') { - def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', dependency.group) - dependencyNode.appendNode('artifactId', dependency.name) - dependencyNode.appendNode('version', dependency.version) - } - } - } - repositories { - def ciJobToken = System.getenv("CI_JOB_TOKEN") - def ciApiV4Url = System.getenv("CI_API_V4_URL") - if (ciJobToken != null) { - maven { - url "${ciApiV4Url}/projects/1269/packages/maven" - credentials(HttpHeaderCredentials) { - name = 'Job-Token' - value = ciJobToken - } - authentication { - header(HttpHeaderAuthentication) - } - } - } else { - maven { - url "https://gitlab.e.foundation/api/v4/projects/1269/packages/maven" - credentials(HttpHeaderCredentials) { - name = "Private-Token" - value = gitLabPrivateToken - } - authentication { - header(HttpHeaderAuthentication) - } - } - } - } - } - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..738ca268326816fc1ccc952e33de39029408fc49 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,23 @@ +/* + * GPlayApi + * Copyright (C) 2020 Aurora OSS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +plugins { + id("com.android.application") version "8.2.1" apply false + id("com.android.library") version "8.2.1" apply false + id("org.jetbrains.kotlin.android") version "1.9.22" apply false + id("org.jetbrains.kotlin.plugin.parcelize") version "1.9.22" apply false + id("com.google.protobuf") version "0.9.4" apply false + id("org.jlleitschuh.gradle.ktlint") version "12.1.0" apply false +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000000000000000000000000000000000..55cce9222e3c44c40ffc3459221e436b13632afc --- /dev/null +++ b/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738cbd051603d91cc39de6cb000dd98fe6b02..d64cd4917707c1f8861d8cb53dd15194d4248596 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09943d3cec348fb9aea8328683ae2f93ee153996..a52e87c12e13a40f8ddb302f4ee21a44535b217d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,21 +1,8 @@ -# -# GPlayApi -# Copyright (C) 2020 Aurora OSS -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# - -#Thu Apr 30 12:26:16 IST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip +#Sat Dec 02 14:38:50 IST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 5912bbfb101641eaa223bef386c229290629c9c0..1aa94a4269074199e6ed2c37e8db3e0826030965 100755 --- a/gradlew +++ b/gradlew @@ -1,93 +1,127 @@ -#!/usr/bin/env sh +#!/bin/sh # -# GPlayApi -# Copyright (C) 2020 Aurora OSS +# Copyright © 2015-2021 the original authors. # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -96,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 0f8d5937c4ad18feb44a19e55ad1e37cc159260f..6689b85beecde676054c39c2408085f41e6be6dc 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,19 +25,23 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 0000000000000000000000000000000000000000..0c8469a468fbce945a671000bdfdff74b386dcee --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,4 @@ +jdk: openjdk17 +install: + - chmod +x gradlew + - ./gradlew :lib:publishToMavenLocal \ No newline at end of file diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9 --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1 @@ +/build diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..58cceaa2ebaef1a288b70c7aa2e5179bb858a10b --- /dev/null +++ b/lib/build.gradle.kts @@ -0,0 +1,118 @@ +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.plugin.parcelize") + id("com.google.protobuf") + id("maven-publish") + id("org.jlleitschuh.gradle.ktlint") +} + +val versionMajor = 3 +val versionMinor = 2 +val versionPatch = 10 +val releasePatch = "1" + +val versionName = "${versionMajor}.${versionMinor}.${versionPatch}-${releasePatch}" + +android { + namespace = "foundation.e.gplayapi" + compileSdk = 34 + + defaultConfig { + minSdk = 21 + aarMetadata { + minCompileSdk = 21 + } + consumerProguardFiles("proguard-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } + packaging { + resources { + excludes += "**/*.proto" + } + } +} + +dependencies { + + implementation("com.google.protobuf:protobuf-javalite:3.25.2") + implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation("com.google.code.gson:gson:2.10.1") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.25.2" + } + generateProtoTasks { + all().forEach { task -> + task.builtins { + create("java") { + option("lite") + } + } + } + } +} + +// Run "./gradlew publishReleasePublicationToLocalRepository" to generate release AAR locally +publishing { + publications { + afterEvaluate { + create("release") { + groupId = "foundation.e" + artifactId = "gplayapi" + version = versionName + from(components["release"]) + } + } + } + + repositories { + val ciJobToken = System.getenv("CI_JOB_TOKEN") + val ciApiV4Url = System.getenv("CI_API_V4_URL") + if (ciJobToken != null) { + maven { + url = uri("${ciApiV4Url}/projects/1269/packages/maven") + name = "GitLab" + credentials(HttpHeaderCredentials::class) { + name = "Job-Token" + value = ciJobToken + } + authentication { + create("header", HttpHeaderAuthentication::class) + } + } + } else { + maven { + url = uri("https://gitlab.e.foundation/api/v4/projects/1269/packages/maven") + name = "GitLab" + credentials(HttpHeaderCredentials::class) { + name = "Private-Token" + value = System.getenv("gitLabPrivateToken") + } + authentication { + create("header", HttpHeaderAuthentication::class) + } + } + } + + maven { + name = "local" + url = uri("./build/repo") + } + } +} diff --git a/lib/proguard-rules.pro b/lib/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..ee6a652638c5149a26f686ee10a4cb709599f638 --- /dev/null +++ b/lib/proguard-rules.pro @@ -0,0 +1,26 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle.kts. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# TODO: Write actual rules +-keep public class com.aurora.gplayapi.** { + *; +} diff --git a/lib/src/main/AndroidManifest.xml b/lib/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..8072ee00dbf16d9161b7464ef3d2194a7d659bcc --- /dev/null +++ b/lib/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/src/main/java/com/aurora/gplayapi/Constants.kt b/lib/src/main/java/com/aurora/gplayapi/Constants.kt similarity index 58% rename from src/main/java/com/aurora/gplayapi/Constants.kt rename to lib/src/main/java/com/aurora/gplayapi/Constants.kt index 60db077fc062f9f86ee298e83602fd014ed4d07d..ee091e77ceb04fb3d3a6702c59023035389b6c46 100644 --- a/src/main/java/com/aurora/gplayapi/Constants.kt +++ b/lib/src/main/java/com/aurora/gplayapi/Constants.kt @@ -46,9 +46,17 @@ object Constants { enum class Restriction(val restriction: Int) { GENERIC(-1), NOT_RESTRICTED(1), - GEO_RESTRICTED(2), + GEO_RESTRICTED(2), // This item isn't available in your country. DEVICE_RESTRICTED(7), - UNKNOWN(9); + NOT_IN_GROUP(8), // You're not in the targeted group for this item. + UNKNOWN(9), + CARRIER_RESTRICTED(10), // This item isn't available on your carrier. + COUNTRY_OR_CARRIER_RESTRICTED(11), // This item isn't available in your country or on your carrier. + PARENTAL_CONTROL_RESTRICTION(12), // Parental controls restrict downloading of this item. + ADMIN_RESTRICTED(21), // Your administrator has not given you access to this item. + ADMIN_PERMISSION_NOT_ACCEPTED(22), // Your administrator has not accepted permissions for this item. + AGE_RESTRICTED(30), // guess: Google user needs to be of full age + APP_OUTDATED(32); // guess: App needs to be updated -> use old device profile for download companion object { fun forInt(restriction: Int): Restriction { @@ -56,10 +64,24 @@ object Constants { 1 -> NOT_RESTRICTED 2 -> GEO_RESTRICTED 7 -> DEVICE_RESTRICTED + 8 -> NOT_IN_GROUP 9 -> UNKNOWN + 10 -> CARRIER_RESTRICTED + 11 -> COUNTRY_OR_CARRIER_RESTRICTED + 12 -> PARENTAL_CONTROL_RESTRICTION + 21 -> ADMIN_RESTRICTED + 22 -> ADMIN_PERMISSION_NOT_ACCEPTED + 30 -> AGE_RESTRICTED + 32 -> APP_OUTDATED else -> GENERIC } } } } -} \ No newline at end of file + + enum class COLLECTION(var value: Array) { + EXACT(arrayOf(0, 1, 0, 23, 16)), + QUERY(arrayOf(0, 1, 1, 21, 0)), + SIMILAR(arrayOf(0, 1, 2, 22, 0)) + } +} diff --git a/src/main/java/com/aurora/gplayapi/DeviceManager.kt b/lib/src/main/java/com/aurora/gplayapi/DeviceManager.kt similarity index 88% rename from src/main/java/com/aurora/gplayapi/DeviceManager.kt rename to lib/src/main/java/com/aurora/gplayapi/DeviceManager.kt index 0f80852c88a8c8afc55a40a86a7eeedb1e3aabf5..f8e20b6077e44670b1f8ba8a1cd632a73a468d80 100644 --- a/src/main/java/com/aurora/gplayapi/DeviceManager.kt +++ b/lib/src/main/java/com/aurora/gplayapi/DeviceManager.kt @@ -16,15 +16,13 @@ package com.aurora.gplayapi import java.io.FileNotFoundException -import java.util.* +import java.util.Properties object DeviceManager { fun loadProperties(deviceName: String?): Properties? { return try { val properties = Properties() - val inputStream = javaClass - .classLoader - .getResourceAsStream(deviceName) + val inputStream = javaClass.classLoader?.getResourceAsStream("gplayapi_$deviceName") if (inputStream != null) { properties.load(inputStream) } else { @@ -35,4 +33,4 @@ object DeviceManager { null } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/FileManager.kt b/lib/src/main/java/com/aurora/gplayapi/FileManager.kt similarity index 98% rename from src/main/java/com/aurora/gplayapi/FileManager.kt rename to lib/src/main/java/com/aurora/gplayapi/FileManager.kt index 3e49d9c50c71d7e6f55787b8bb78ab829b746b87..46ef9e5572bc0b6ee8c60f640281724fdf4ee5d9 100644 --- a/src/main/java/com/aurora/gplayapi/FileManager.kt +++ b/lib/src/main/java/com/aurora/gplayapi/FileManager.kt @@ -17,7 +17,6 @@ package com.aurora.gplayapi import java.io.BufferedReader import java.io.InputStreamReader -import java.util.* object FileManager { fun loadPackages(fileName: String?): List? { @@ -34,4 +33,4 @@ object FileManager { null } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/GooglePlayApi.kt b/lib/src/main/java/com/aurora/gplayapi/GooglePlayApi.kt similarity index 95% rename from src/main/java/com/aurora/gplayapi/GooglePlayApi.kt rename to lib/src/main/java/com/aurora/gplayapi/GooglePlayApi.kt index 577ff178217f51d2186024560f4a38d7bc43044a..f33a6f43ba1101e8c2890236f17a31ef96e52e01 100644 --- a/src/main/java/com/aurora/gplayapi/GooglePlayApi.kt +++ b/lib/src/main/java/com/aurora/gplayapi/GooglePlayApi.kt @@ -15,7 +15,6 @@ package com.aurora.gplayapi -import com.aurora.gplayapi.GooglePlayApi.Service.* import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.providers.DeviceInfoProvider import com.aurora.gplayapi.data.providers.HeaderProvider.getAuthHeaders @@ -29,7 +28,6 @@ import com.aurora.gplayapi.network.IHttpClient import com.aurora.gplayapi.utils.Util import java.io.IOException import java.math.BigInteger -import java.util.* class GooglePlayApi(private val authData: AuthData) { @@ -129,37 +127,44 @@ class GooglePlayApi(private val authData: AuthData) { params.putAll(getAuthParams(aasToken)) when (service) { - AC2DM -> { + Service.AC2DM -> { params["service"] = "ac2dm" params.remove("app") } - ANDROID_CHECK_IN_SERVER -> { + + Service.ANDROID_CHECK_IN_SERVER -> { params["oauth2_foreground"] = "0" params["app"] = "com.google.android.gms" params["service"] = "AndroidCheckInServer" } - EXPERIMENTAL_CONFIG -> { + + Service.EXPERIMENTAL_CONFIG -> { params["service"] = "oauth2:https://www.googleapis.com/auth/experimentsandconfigs" } - NUMBERER -> { + + Service.NUMBERER -> { params["app"] = "com.google.android.gms" params["service"] = "oauth2:https://www.googleapis.com/auth/numberer" } - GCM -> { + + Service.GCM -> { params["app"] = "com.google.android.gms" params["service"] = "oauth2:https://www.googleapis.com/auth/gcm" } - GOOGLE_PLAY -> { + + Service.GOOGLE_PLAY -> { headers["app"] = "com.google.android.gms" params["service"] = "oauth2:https://www.googleapis.com/auth/googleplay" } - OAUTHLOGIN -> { + + Service.OAUTHLOGIN -> { params["oauth2_foreground"] = "0" params["app"] = "com.google.android.googlequicksearchbox" params["service"] = "oauth2:https://www.google.com/accounts/OAuthLogin" params["callerPkg"] = "com.google.android.googlequicksearchbox" } - ANDROID -> { + + Service.ANDROID -> { params["service"] = "android" } } @@ -168,7 +173,7 @@ class GooglePlayApi(private val authData: AuthData) { val hashMap = Util.parseResponse(playResponse.responseBytes) return if (hashMap.containsKey("Auth")) { - hashMap.getOrDefault("Auth", "") + hashMap["Auth"] ?: "" } else { throw AuthException("Authentication failed : Could not generate OAuth Token") } @@ -217,7 +222,7 @@ class GooglePlayApi(private val authData: AuthData) { const val URL_LIBRARY = "$URL_FDFE/library" const val URL_MODIFY_LIBRARY = "$URL_FDFE/modifyLibrary" - //Not part of Google's API + // Not part of Google's API const val SALES_URL = "https://www.bestappsale.com/api/android/getsale.php" } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/builders/AppBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/AppBuilder.kt similarity index 87% rename from src/main/java/com/aurora/gplayapi/data/builders/AppBuilder.kt rename to lib/src/main/java/com/aurora/gplayapi/data/builders/AppBuilder.kt index 7ecb109ffd234c0ae353f9ed6568300daec0eefa..e2b4534d8948096a1ae594a3d5544e3d5c0da983 100644 --- a/src/main/java/com/aurora/gplayapi/data/builders/AppBuilder.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/AppBuilder.kt @@ -19,7 +19,9 @@ import com.aurora.gplayapi.AppDetails import com.aurora.gplayapi.Constants import com.aurora.gplayapi.DetailsResponse import com.aurora.gplayapi.Item +import com.aurora.gplayapi.data.models.ActiveDevice import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.data.models.EncodedCertificateSet import com.aurora.gplayapi.data.models.File import com.aurora.gplayapi.data.models.details.Badge import com.aurora.gplayapi.data.models.details.Chip @@ -81,13 +83,28 @@ object AppBuilder { app.targetSdk = appDetails.targetSdkVersion app.updatedOn = appDetails.infoUpdatedOn - if (app.developerName.isEmpty()) + if (app.developerName.isEmpty()) { app.developerName = item.creator + } appDetails.instantLink?.let { app.instantAppLink = it } + app.certificateHashList.addAll(appDetails.certificateHashList) + + app.certificateSetList.addAll( + appDetails.certificateSetList.map { + EncodedCertificateSet(it.certificateHash, it.sha256) + } + ) + + app.compatibility.addAll( + appDetails.compatibility.activeDevicesList.map { + ActiveDevice(name = it.name, requiredOS = it.requiredOS) + } + ) + parseEditorReasons(app, item) parseAppInfo(app, item) parseChips(app, item) @@ -188,6 +205,13 @@ object AppBuilder { dependentSplits.add(splitId) } + it.libraryDependencyList.forEach { dependency -> + var libApp = App(dependency.packageName) + libApp.versionCode = dependency.versionCode + libApp.offerType = 1 + dependentLibraries.add(libApp) + } + totalSize = it.size targetSDK = it.targetSdk } @@ -205,6 +229,10 @@ object AppBuilder { } appInfoMap["DOWNLOAD"] = item.details.appDetails.infoDownload appInfoMap["UPDATED_ON"] = item.details.appDetails.infoUpdatedOn + val minAndroidVersion = + app.compatibility.map { it.requiredOS.split(" ")[0].toFloatOrNull() ?: 1F } + .minOfOrNull { it } ?: 1F + appInfoMap["REQUIRES"] = "Android $minAndroidVersion and up" } } } @@ -252,7 +280,8 @@ object AppBuilder { } private fun getInstalls(downloadInfo: String): Long { - val matcher: Matcher = Pattern.compile("[\\d]+").matcher(downloadInfo.replace("[,.\\s]+".toRegex(), "")) + val matcher: Matcher = + Pattern.compile("[\\d]+").matcher(downloadInfo.replace("[,.\\s]+".toRegex(), "")) return if (matcher.find()) Util.parseLong(matcher.group(0), 0) else 0 } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/builders/ArtworkBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/ArtworkBuilder.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/builders/ArtworkBuilder.kt rename to lib/src/main/java/com/aurora/gplayapi/data/builders/ArtworkBuilder.kt index a155af21e3c247eaccd8db86c8b6c9fd497ee4cb..417cd60b70482affea74055c66b59676f3f7c458 100644 --- a/src/main/java/com/aurora/gplayapi/data/builders/ArtworkBuilder.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/ArtworkBuilder.kt @@ -29,4 +29,4 @@ object ArtworkBuilder { height = image.dimension.height } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/builders/BadgeBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/BadgeBuilder.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/builders/BadgeBuilder.kt rename to lib/src/main/java/com/aurora/gplayapi/data/builders/BadgeBuilder.kt index d566049204a8163916fbcfeb041974b323334e0e..586ce80454c294d8d7efb18f51190de68f24024f 100644 --- a/src/main/java/com/aurora/gplayapi/data/builders/BadgeBuilder.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/BadgeBuilder.kt @@ -29,4 +29,4 @@ object BadgeBuilder { link = badge.link.toString() } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/builders/RatingBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/RatingBuilder.kt similarity index 67% rename from src/main/java/com/aurora/gplayapi/data/builders/RatingBuilder.kt rename to lib/src/main/java/com/aurora/gplayapi/data/builders/RatingBuilder.kt index 5e00c54ac7ac403803ff3f3d580edf77003160b0..ef5fec68113d58919aa408a83c21557fdb54bc14 100644 --- a/src/main/java/com/aurora/gplayapi/data/builders/RatingBuilder.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/RatingBuilder.kt @@ -22,16 +22,16 @@ object RatingBuilder { fun build(rating: AggregateRating): Rating { return Rating( - rating.starRating, - rating.oneStarRatings, - rating.twoStarRatings, - rating.threeStarRatings, - rating.fourStarRatings, - rating.fiveStarRatings, - rating.thumbsUpCount, - rating.thumbsDownCount, - rating.ratingLabel, - rating.ratingCountLabelAbbreviated + rating.starRating, + rating.oneStarRatings, + rating.twoStarRatings, + rating.threeStarRatings, + rating.fourStarRatings, + rating.fiveStarRatings, + rating.thumbsUpCount, + rating.thumbsDownCount, + rating.ratingLabel, + rating.ratingCountLabelAbbreviated ) } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/builders/ReviewBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/ReviewBuilder.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/builders/ReviewBuilder.kt rename to lib/src/main/java/com/aurora/gplayapi/data/builders/ReviewBuilder.kt index 4d4ab3428e92095ff99d97ec5733448192b4a218..5382646a180bc266cfe3ff00537c3e17e497845e 100644 --- a/src/main/java/com/aurora/gplayapi/data/builders/ReviewBuilder.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/ReviewBuilder.kt @@ -37,4 +37,4 @@ object ReviewBuilder { } } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/builders/TestingProgramBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/TestingProgramBuilder.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/builders/TestingProgramBuilder.kt rename to lib/src/main/java/com/aurora/gplayapi/data/builders/TestingProgramBuilder.kt index 9d91edc27eff75d5feb66cc1b0327ed0054dc5f9..87fa5f102f7fc3c414a6b54549d98b02bd24037c 100644 --- a/src/main/java/com/aurora/gplayapi/data/builders/TestingProgramBuilder.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/TestingProgramBuilder.kt @@ -36,4 +36,4 @@ object TestingProgramBuilder { null } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/builders/UserProfileBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/UserProfileBuilder.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/builders/UserProfileBuilder.kt rename to lib/src/main/java/com/aurora/gplayapi/data/builders/UserProfileBuilder.kt index 56658cb7484f90480d1201a69131739059b40c23..2efb6863a43554853c2a2c01af3f732fdda71bf2 100644 --- a/src/main/java/com/aurora/gplayapi/data/builders/UserProfileBuilder.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/UserProfileBuilder.kt @@ -17,7 +17,6 @@ package com.aurora.gplayapi.data.builders import com.aurora.gplayapi.data.models.UserProfile - object UserProfileBuilder { fun build(userProfileProto: com.aurora.gplayapi.UserProfile): UserProfile { @@ -27,4 +26,4 @@ object UserProfileBuilder { artwork = ArtworkBuilder.build(userProfileProto.getImage(0)) } } -} \ No newline at end of file +} diff --git a/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/RpcBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/RpcBuilder.kt new file mode 100644 index 0000000000000000000000000000000000000000..b4808dc53b2f7788d17e9581f89759a9c798afd8 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/RpcBuilder.kt @@ -0,0 +1,30 @@ +package com.aurora.gplayapi.data.builders.rpc + +import com.aurora.gplayapi.utils.dig +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken + +object RpcBuilder { + fun wrapResponse(input: String): HashMap?> { + val lines = input.lines() + val filteredLines = lines.filter { it.startsWith("[[\"wrb.fr") } + val result = HashMap?>() + + filteredLines.forEach { + val jaggedProto = parseJaggedString(it) + val (type, packageName) = (jaggedProto.dig(0, 6)).toString().split("@") + + result[type] = hashMapOf( + packageName to parseJaggedString(jaggedProto.dig(0, 2)) + ) + } + + return result + } + + private fun parseJaggedString(input: String?): Collection { + val gson = Gson() + val arrayType = object : TypeToken>() {}.type + return gson.fromJson(input, arrayType) + } +} diff --git a/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/SearchQueryBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/SearchQueryBuilder.kt new file mode 100644 index 0000000000000000000000000000000000000000..5a193893a449f5aec6dac6ae66a8aaaf2472d201 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/SearchQueryBuilder.kt @@ -0,0 +1,20 @@ +package com.aurora.gplayapi.data.builders.rpc + +object SearchQueryBuilder { + public val TAG = "SQB" + + private val SEARCH_TOKEN = + "[[10,[10,50]],true,null,[96,27,4,8,57,30,110,11,16,49,1,9,12,104,55,56,51,10,34,31,145],[null,null,[[null,null,[[[]]]],[null,[[[]]]],[null,[[[]]]],[null,[[[]]]],null,null,null,null,[[[[]]]],[[[[]]]]],[[[[7,1],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,31],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,104],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,9],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,8],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,27],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,49],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,12],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,65],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,110],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,88],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,11],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,56],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,55],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,96],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,122],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,72],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,71],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,64],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[7,113],[[1,73,96,103,58,92,52,112,69,19,31,101,123,74,49,80,20,10,14,79,43]]],[[9,1],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,31],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,104],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,9],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,8],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,27],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,49],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,12],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,65],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,110],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,88],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,11],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,56],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,55],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,96],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,122],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,72],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,71],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,64],[[1,7,9,24,12,31,5,10,15,27,8]]],[[9,113],[[1,7,9,24,12,31,5,10,15,27,8]]],[[17,1],[[1,7,9,25,13,31,5,10,27,8]]],[[17,31],[[1,7,9,25,13,31,5,10,27,8]]],[[17,104],[[1,7,9,25,13,31,5,10,27,8]]],[[17,9],[[1,7,9,25,13,31,5,10,27,8]]],[[17,8],[[1,7,9,25,13,31,5,10,27,8]]],[[17,27],[[1,7,9,25,13,31,5,10,27,8]]],[[17,49],[[1,7,9,25,13,31,5,10,27,8]]],[[17,12],[[1,7,9,25,13,31,5,10,27,8]]],[[17,65],[[1,7,9,25,13,31,5,10,27,8]]],[[17,110],[[1,7,9,25,13,31,5,10,27,8]]],[[17,88],[[1,7,9,25,13,31,5,10,27,8]]],[[17,11],[[1,7,9,25,13,31,5,10,27,8]]],[[17,56],[[1,7,9,25,13,31,5,10,27,8]]],[[17,55],[[1,7,9,25,13,31,5,10,27,8]]],[[17,96],[[1,7,9,25,13,31,5,10,27,8]]],[[17,122],[[1,7,9,25,13,31,5,10,27,8]]],[[17,72],[[1,7,9,25,13,31,5,10,27,8]]],[[17,71],[[1,7,9,25,13,31,5,10,27,8]]],[[17,64],[[1,7,9,25,13,31,5,10,27,8]]],[[17,113],[[1,7,9,25,13,31,5,10,27,8]]],[[10,1],[[1,7,6,9]]],[[10,31],[[1,7,6,9]]],[[10,104],[[1,7,6,9]]],[[10,9],[[1,7,6,9]]],[[10,8],[[1,7,6,9]]],[[10,27],[[1,7,6,9]]],[[10,49],[[1,7,6,9]]],[[10,12],[[1,7,6,9]]],[[10,65],[[1,7,6,9]]],[[10,110],[[1,7,6,9]]],[[10,88],[[1,7,6,9]]],[[10,11],[[1,7,6,9]]],[[10,56],[[1,7,6,9]]],[[10,55],[[1,7,6,9]]],[[10,96],[[1,7,6,9]]],[[10,122],[[1,7,6,9]]],[[10,72],[[1,7,6,9]]],[[10,71],[[1,7,6,9]]],[[10,64],[[1,7,6,9]]],[[10,113],[[1,7,6,9]]],[[1,1],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,31],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,104],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,9],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,8],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,27],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,49],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,12],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,65],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,110],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,88],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,11],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,56],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,55],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,96],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,122],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,72],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,71],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,64],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[1,113],[[1,5,14,38,19,29,7,34,4,12,11,6,30,16,10]]],[[4,1],[[1,3,5,4,7,6,11,19]]],[[4,31],[[1,3,5,4,7,6,11,19]]],[[4,104],[[1,3,5,4,7,6,11,19]]],[[4,9],[[1,3,5,4,7,6,11,19]]],[[4,8],[[1,3,5,4,7,6,11,19]]],[[4,27],[[1,3,5,4,7,6,11,19]]],[[4,49],[[1,3,5,4,7,6,11,19]]],[[4,12],[[1,3,5,4,7,6,11,19]]],[[4,65],[[1,3,5,4,7,6,11,19]]],[[4,110],[[1,3,5,4,7,6,11,19]]],[[4,88],[[1,3,5,4,7,6,11,19]]],[[4,11],[[1,3,5,4,7,6,11,19]]],[[4,56],[[1,3,5,4,7,6,11,19]]],[[4,55],[[1,3,5,4,7,6,11,19]]],[[4,96],[[1,3,5,4,7,6,11,19]]],[[4,122],[[1,3,5,4,7,6,11,19]]],[[4,72],[[1,3,5,4,7,6,11,19]]],[[4,71],[[1,3,5,4,7,6,11,19]]],[[4,64],[[1,3,5,4,7,6,11,19]]],[[4,113],[[1,3,5,4,7,6,11,19]]],[[3,1],[[1,5,14,4,10,17]]],[[3,31],[[1,5,14,4,10,17]]],[[3,104],[[1,5,14,4,10,17]]],[[3,9],[[1,5,14,4,10,17]]],[[3,8],[[1,5,14,4,10,17]]],[[3,27],[[1,5,14,4,10,17]]],[[3,49],[[1,5,14,4,10,17]]],[[3,12],[[1,5,14,4,10,17]]],[[3,65],[[1,5,14,4,10,17]]],[[3,110],[[1,5,14,4,10,17]]],[[3,88],[[1,5,14,4,10,17]]],[[3,11],[[1,5,14,4,10,17]]],[[3,56],[[1,5,14,4,10,17]]],[[3,55],[[1,5,14,4,10,17]]],[[3,96],[[1,5,14,4,10,17]]],[[3,122],[[1,5,14,4,10,17]]],[[3,72],[[1,5,14,4,10,17]]],[[3,71],[[1,5,14,4,10,17]]],[[3,64],[[1,5,14,4,10,17]]],[[3,113],[[1,5,14,4,10,17]]],[[2,1],[[1,5,7,18,4,13,16,12]]],[[2,31],[[1,5,7,18,4,13,16,12]]],[[2,104],[[1,5,7,18,4,13,16,12]]],[[2,9],[[1,5,7,18,4,13,16,12]]],[[2,8],[[1,5,7,18,4,13,16,12]]],[[2,27],[[1,5,7,18,4,13,16,12]]],[[2,49],[[1,5,7,18,4,13,16,12]]],[[2,12],[[1,5,7,18,4,13,16,12]]],[[2,65],[[1,5,7,18,4,13,16,12]]],[[2,110],[[1,5,7,18,4,13,16,12]]],[[2,88],[[1,5,7,18,4,13,16,12]]],[[2,11],[[1,5,7,18,4,13,16,12]]],[[2,56],[[1,5,7,18,4,13,16,12]]],[[2,55],[[1,5,7,18,4,13,16,12]]],[[2,96],[[1,5,7,18,4,13,16,12]]],[[2,122],[[1,5,7,18,4,13,16,12]]],[[2,72],[[1,5,7,18,4,13,16,12]]],[[2,71],[[1,5,7,18,4,13,16,12]]],[[2,64],[[1,5,7,18,4,13,16,12]]],[[2,113],[[1,5,7,18,4,13,16,12]]]]]]]" + + fun build(query: String, nextPageToken: String = "", tag: String = TAG): String { + return if (nextPageToken.isNotEmpty()) { + """ + ["qnKhOb","[[null,$SEARCH_TOKEN,null,\"$nextPageToken\"]]",null,"$tag@$query"] + """.trim() + } else { + """ + ["lGYRle","[[[],$SEARCH_TOKEN,[\"$query\"],4,[null,1],null,null,[]]]",null,"$tag@$query"] + """.trim() + } + } +} diff --git a/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/SearchSuggestionQueryBuilder.kt b/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/SearchSuggestionQueryBuilder.kt new file mode 100644 index 0000000000000000000000000000000000000000..a9298549e4886cf203b96a82ab511485dcd4b32f --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/data/builders/rpc/SearchSuggestionQueryBuilder.kt @@ -0,0 +1,13 @@ +package com.aurora.gplayapi.data.builders.rpc + +object SearchSuggestionQueryBuilder { + public val TAG = "SSQB" + fun build(query: String, tag: String = TAG): String { + return """ + ["teXCtc","[null,[\"$query\"],[10],[2,1],4]",null,"$tag@$query"] + """ + .trimStart() + .trimEnd() + .trimIndent() + } +} diff --git a/lib/src/main/java/com/aurora/gplayapi/data/models/ActiveDevice.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/ActiveDevice.kt new file mode 100644 index 0000000000000000000000000000000000000000..9fe2dc952970cf42dc365d708f437d51d7f66ecb --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/ActiveDevice.kt @@ -0,0 +1,10 @@ +package com.aurora.gplayapi.data.models + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class ActiveDevice( + val name: String = String(), + val requiredOS: String = String() +) : Parcelable diff --git a/lib/src/main/java/com/aurora/gplayapi/data/models/App.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/App.kt new file mode 100644 index 0000000000000000000000000000000000000000..4d9b367f4f6e146c5772fef3226441d0b8fab820 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/App.kt @@ -0,0 +1,100 @@ +/* + * GPlayApi + * Copyright (C) 2020 Aurora OSS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +package com.aurora.gplayapi.data.models + +import android.os.Parcelable +import com.aurora.gplayapi.Constants.Restriction +import com.aurora.gplayapi.data.models.details.AppInfo +import com.aurora.gplayapi.data.models.details.Badge +import com.aurora.gplayapi.data.models.details.Chip +import com.aurora.gplayapi.data.models.details.Dependencies +import com.aurora.gplayapi.data.models.details.TestingProgram +import com.aurora.gplayapi.data.models.editor.EditorChoiceReason +import kotlinx.parcelize.Parcelize + +@Parcelize +data class App( + var packageName: String, + var id: Int = 0, + var appInfo: AppInfo = AppInfo(), + var categoryArtwork: Artwork = Artwork(), + var categoryId: Int = 0, + var categoryName: String = String(), + var categoryStreamUrl: String? = String(), + var changes: String = String(), + var chips: MutableList = mutableListOf(), + var containsAds: Boolean = false, + var coverArtwork: Artwork = Artwork(), + var dependencies: Dependencies = Dependencies(), + var description: String = String(), + var detailsStreamUrl: String? = String(), + var detailsPostAcquireStreamUrl: String? = String(), + var developerAddress: String = String(), + var developerEmail: String = String(), + var developerName: String = String(), + var developerWebsite: String = String(), + var displayBadges: MutableList = mutableListOf(), + var displayName: String = String(), + var editorReason: EditorChoiceReason? = null, + var downloadString: String = String(), + var earlyAccess: Boolean = false, + var fileList: MutableList = mutableListOf(), + var footerHtml: String = String(), + var iconArtwork: Artwork = Artwork(), + var infoBadges: MutableList = mutableListOf(), + var inPlayStore: Boolean = false, + var installs: Long = 0, + var instantAppLink: String = String(), + var isFree: Boolean = false, + var isInstalled: Boolean = false, + var isSystem: Boolean = false, + var labeledRating: String = String(), + var liveStreamUrl: String? = String(), + var offerDetails: MutableMap = mutableMapOf(), + var offerType: Int = 0, + var permissions: MutableList = mutableListOf(), + var price: String = String(), + var promotionStreamUrl: String? = String(), + var rating: Rating = Rating(), + var relatedLinks: MutableMap = mutableMapOf(), + var restriction: Restriction = Restriction.NOT_RESTRICTED, + var screenshots: MutableList = mutableListOf(), + var shareUrl: String = String(), + var shortDescription: String = String(), + var size: Long = 0, + var targetSdk: Int = 21, + var testingProgram: TestingProgram? = null, + var userReview: Review = Review(), + var updatedOn: String = String(), + var versionCode: Int = 0, + var versionName: String = String(), + var videoArtwork: Artwork = Artwork(), + var certificateHashList: MutableList = mutableListOf(), + var certificateSetList: MutableList = mutableListOf(), + val compatibility: MutableList = mutableListOf() +) : Parcelable { + + override fun hashCode(): Int { + return packageName.hashCode() + } + + override fun equals(other: Any?): Boolean { + return when (other) { + is App -> packageName == other.packageName + else -> false + } + } +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/Artwork.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/Artwork.kt similarity index 77% rename from src/main/java/com/aurora/gplayapi/data/models/Artwork.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/Artwork.kt index 8f8b207308251b7bc9c201ad884ceedc25d12666..2b8607c28d2e474fceec491ba01f8d2e3a6ede1f 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/Artwork.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/Artwork.kt @@ -15,13 +15,18 @@ package com.aurora.gplayapi.data.models -class Artwork { - var type: Int = 0 - var url: String = String() - var urlAlt: String = String() - var aspectRatio: Int = 0 - var width: Int = 0 +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class Artwork( + var type: Int = 0, + var url: String = String(), + var urlAlt: String = String(), + var aspectRatio: Int = 0, + var width: Int = 0, var height: Int = 0 +) : Parcelable { override fun hashCode(): Int { return url.hashCode() @@ -33,4 +38,4 @@ class Artwork { else -> false } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/AuthData.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/AuthData.kt similarity index 94% rename from src/main/java/com/aurora/gplayapi/data/models/AuthData.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/AuthData.kt index a23dafdffc41d44b7540cc85b545164fa25b8f96..fa7095db844ab562155bcdfc4c2e7e22ebdd3de8 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/AuthData.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/AuthData.kt @@ -16,7 +16,7 @@ package com.aurora.gplayapi.data.models import com.aurora.gplayapi.data.providers.DeviceInfoProvider -import java.util.* +import java.util.Locale class AuthData { @@ -27,7 +27,7 @@ class AuthData { this.aasToken = aasToken } - constructor(email: String, authToken: String, insecure : Boolean = true) { + constructor(email: String, authToken: String, insecure: Boolean = true) { this.email = email this.authToken = authToken this.isAnonymous = true @@ -52,4 +52,4 @@ class AuthData { get() = field ?: DeviceInfoProvider.getDefault() var userProfile: UserProfile? = null -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/Category.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/Category.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/models/Category.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/Category.kt index 2383effaeafbcd1c2f918c5707da5fe74d521fad..3aed6654bf542bd870680664356d64777923d9ba 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/Category.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/Category.kt @@ -37,4 +37,4 @@ class Category { else -> false } } -} \ No newline at end of file +} diff --git a/lib/src/main/java/com/aurora/gplayapi/data/models/EncodedCertificateSet.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/EncodedCertificateSet.kt new file mode 100644 index 0000000000000000000000000000000000000000..b83aa2c11114c1cc1368edd2f2deb594cc82db5d --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/EncodedCertificateSet.kt @@ -0,0 +1,10 @@ +package com.aurora.gplayapi.data.models + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class EncodedCertificateSet( + val certificateSet: String, + val sha256: String +) : Parcelable diff --git a/src/main/java/com/aurora/gplayapi/data/models/File.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/File.kt similarity index 71% rename from src/main/java/com/aurora/gplayapi/data/models/File.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/File.kt index c66e7fdebefb17b26a3ea622aa7e1724986d6657..298d9594f063efc9c8c8e8a73fbae905608d2e1e 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/File.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/File.kt @@ -15,14 +15,20 @@ package com.aurora.gplayapi.data.models -import java.util.* +import android.os.Parcelable +import kotlinx.parcelize.Parcelize +import java.util.UUID -class File { - var id: String = UUID.randomUUID().toString() - var name: String = String() - var url: String = String() - var size: Long = 0L - var type: FileType = FileType.BASE +@Parcelize +data class File( + var id: String = UUID.randomUUID().toString(), + var name: String = String(), + var url: String = String(), + var size: Long = 0L, + var type: FileType = FileType.BASE, + var sha1: String = String(), + var sha256: String = String() +) : Parcelable { enum class FileType { BASE, OBB, PATCH, SPLIT @@ -38,4 +44,4 @@ class File { else -> false } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/PlayResponse.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/PlayResponse.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/models/PlayResponse.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/PlayResponse.kt index f62ecfdf5c1ebd9a9f43621f8718760676e5fca4..baa159d8501e5ae3ae0f83493085f356e81b6384 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/PlayResponse.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/PlayResponse.kt @@ -21,4 +21,4 @@ class PlayResponse { var errorString: String = ("No Error") var isSuccessful: Boolean = false var code: Int = 0 -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/Rating.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/Rating.kt similarity index 62% rename from src/main/java/com/aurora/gplayapi/data/models/Rating.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/Rating.kt index 84e3d76b7073cedea37a2ecc7ce1208616df710b..78f19ac8f90cafa5d21ec11f787ba76cbeb8c570 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/Rating.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/Rating.kt @@ -15,15 +15,19 @@ package com.aurora.gplayapi.data.models +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize data class Rating( - var average: Float = 0f, - var oneStar: Long = 0L, - var twoStar: Long = 0L, - var threeStar: Long = 0L, - var fourStar: Long = 0L, - var fiveStar: Long = 0L, - var thumbsUp: Long = 0L, - var thumbsDown: Long = 0L, - var label: String = String(), - var abbreviatedLabel: String = String() -) + var average: Float = 0f, + var oneStar: Long = 0L, + var twoStar: Long = 0L, + var threeStar: Long = 0L, + var fourStar: Long = 0L, + var fiveStar: Long = 0L, + var thumbsUp: Long = 0L, + var thumbsDown: Long = 0L, + var label: String = String(), + var abbreviatedLabel: String = String() +) : Parcelable diff --git a/src/main/java/com/aurora/gplayapi/data/models/Review.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/Review.kt similarity index 75% rename from src/main/java/com/aurora/gplayapi/data/models/Review.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/Review.kt index 0fbe3c3836497ae8a710549c3aea685b80f56133..b8674054c93dd7292eb692f877212d176c353003 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/Review.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/Review.kt @@ -15,15 +15,20 @@ package com.aurora.gplayapi.data.models -class Review { - var title: String = String() - var comment: String = String() - var commentId: String = String() - var userName: String = String() - var userPhotoUrl: String = String() - var appVersion: String = String() - var rating: Int = 0 +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class Review( + var title: String = String(), + var comment: String = String(), + var commentId: String = String(), + var userName: String = String(), + var userPhotoUrl: String = String(), + var appVersion: String = String(), + var rating: Int = 0, var timeStamp: Long = 0L +) : Parcelable { override fun hashCode(): Int { return commentId.hashCode() diff --git a/src/main/java/com/aurora/gplayapi/data/models/ReviewCluster.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/ReviewCluster.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/models/ReviewCluster.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/ReviewCluster.kt index 8755f0b67a7d72ea3651ef5307cc9e824a12cf6f..8ab8f21ec414aef7a81ef833803633dee2c1e3c1 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/ReviewCluster.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/ReviewCluster.kt @@ -23,4 +23,4 @@ class ReviewCluster { fun hasNext(): Boolean { return nextPageUrl.isNotBlank() } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/SearchBundle.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/SearchBundle.kt similarity index 98% rename from src/main/java/com/aurora/gplayapi/data/models/SearchBundle.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/SearchBundle.kt index 7512bfdb83860da869757fb9053fa5c2b18910cf..56276285beef3488959425a4b6e148ef89411309 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/SearchBundle.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/SearchBundle.kt @@ -15,8 +15,6 @@ package com.aurora.gplayapi.data.models -import java.util.* - class SearchBundle { var id: Int = -1 var query: String = String() @@ -40,4 +38,4 @@ class SearchBundle { } } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/StreamBundle.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/StreamBundle.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/models/StreamBundle.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/StreamBundle.kt index 95a1727f0af15ca33edeef72de49548c1c38b7e5..e9a7ac26c65dd2648a2ba3712b30f74afc045b39 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/StreamBundle.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/StreamBundle.kt @@ -28,4 +28,4 @@ class StreamBundle { fun hasCluster(): Boolean { return streamClusters.isNotEmpty() } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/StreamCluster.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/StreamCluster.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/models/StreamCluster.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/StreamCluster.kt index 98f13a2c2028f6cd835c5ba548eee5791596949d..b359201d447c8303d0116b55ca287c486cca376e 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/StreamCluster.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/StreamCluster.kt @@ -26,4 +26,4 @@ class StreamCluster { fun hasNext(): Boolean { return clusterNextPageUrl.isNotBlank() } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/UserProfile.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/UserProfile.kt similarity index 100% rename from src/main/java/com/aurora/gplayapi/data/models/UserProfile.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/UserProfile.kt diff --git a/src/main/java/com/aurora/gplayapi/data/models/details/AppInfo.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/details/AppInfo.kt similarity index 79% rename from src/main/java/com/aurora/gplayapi/data/models/details/AppInfo.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/details/AppInfo.kt index 33b09bf61514ab311d667127f9400516a8c863d7..b8fbdf022a751ca32ff1d6d9285e3ff90cd83507 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/details/AppInfo.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/details/AppInfo.kt @@ -15,6 +15,8 @@ package com.aurora.gplayapi.data.models.details -class AppInfo { - var appInfoMap: MutableMap = mutableMapOf() -} \ No newline at end of file +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class AppInfo(var appInfoMap: MutableMap = mutableMapOf()) : Parcelable diff --git a/src/main/java/com/aurora/gplayapi/data/models/details/Badge.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/details/Badge.kt similarity index 71% rename from src/main/java/com/aurora/gplayapi/data/models/details/Badge.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/details/Badge.kt index 07e5b988acbf65d6ad475eef9f7bd057837dfe5c..850c79025403203ee7c641f6c5d51376ed3292c2 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/details/Badge.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/details/Badge.kt @@ -15,17 +15,21 @@ package com.aurora.gplayapi.data.models.details +import android.os.Parcelable import com.aurora.gplayapi.data.models.Artwork -import java.util.* +import kotlinx.parcelize.Parcelize +import java.util.UUID -class Badge { - var id: String = UUID.randomUUID().toString() - var textMajor: String = String() - var textMinor: String = String() - var textMinorHtml: String? = String() - var textDescription: String? = String() - var artwork: Artwork? = null +@Parcelize +data class Badge( + var id: String = UUID.randomUUID().toString(), + var textMajor: String = String(), + var textMinor: String = String(), + var textMinorHtml: String? = String(), + var textDescription: String? = String(), + var artwork: Artwork? = null, var link: String = String() +) : Parcelable { override fun equals(other: Any?): Boolean { return when (other) { @@ -37,4 +41,4 @@ class Badge { override fun hashCode(): Int { return id.hashCode() } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/details/Chip.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/details/Chip.kt similarity index 80% rename from src/main/java/com/aurora/gplayapi/data/models/details/Chip.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/details/Chip.kt index 4c20e6f8828a72ed39557dbb0c8cc159f9b97603..20962705f785c9336e774805c052b48e3dd99ef6 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/details/Chip.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/details/Chip.kt @@ -15,12 +15,16 @@ package com.aurora.gplayapi.data.models.details -import java.util.* +import android.os.Parcelable +import kotlinx.parcelize.Parcelize +import java.util.UUID -class Chip { - var id: String = UUID.randomUUID().toString() - var title: String = String() +@Parcelize +data class Chip( + var id: String = UUID.randomUUID().toString(), + var title: String = String(), var streamUrl: String? = String() +) : Parcelable { override fun hashCode(): Int { return id.hashCode() @@ -32,4 +36,4 @@ class Chip { else -> false } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/details/Dependencies.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/details/Dependencies.kt similarity index 63% rename from src/main/java/com/aurora/gplayapi/data/models/details/Dependencies.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/details/Dependencies.kt index d08298f87247eb7b6a58242302564c4818aa211c..893ae1052646b95067333f94b7bc3f428c05698b 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/details/Dependencies.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/details/Dependencies.kt @@ -15,9 +15,15 @@ package com.aurora.gplayapi.data.models.details -class Dependencies { - var dependentPackages = mutableListOf() - var dependentSplits = mutableListOf() - var targetSDK: Int = -1 +import android.os.Parcelable +import com.aurora.gplayapi.data.models.App +import kotlinx.parcelize.Parcelize + +@Parcelize +data class Dependencies( + var dependentPackages: MutableList = mutableListOf(), + var dependentSplits: MutableList = mutableListOf(), + var dependentLibraries: MutableList = mutableListOf(), + var targetSDK: Int = -1, var totalSize: Long = -1L -} \ No newline at end of file +) : Parcelable diff --git a/src/main/java/com/aurora/gplayapi/data/models/details/DevStream.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/details/DevStream.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/models/details/DevStream.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/details/DevStream.kt index 5702e9fb4a444751cd8e2e8431b209be82dfe425..d8dd6476d8ee860351bb93de674e232f92951472 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/details/DevStream.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/details/DevStream.kt @@ -22,4 +22,4 @@ class DevStream { var description: String = String() var imgUrl: String = String() var streamBundle: StreamBundle = StreamBundle() -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/details/TestingProgram.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/details/TestingProgram.kt similarity index 69% rename from src/main/java/com/aurora/gplayapi/data/models/details/TestingProgram.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/details/TestingProgram.kt index f96c5c8494ebe053af05d82e4062976421119845..3dffb1894059a86148ea8729e4dd391ee0987c28 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/details/TestingProgram.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/details/TestingProgram.kt @@ -15,18 +15,22 @@ package com.aurora.gplayapi.data.models.details +import android.os.Parcelable import com.aurora.gplayapi.data.models.Artwork +import kotlinx.parcelize.Parcelize -class TestingProgram { - var artwork: Artwork = Artwork() - var displayName: String = String() - var email: String = String() - var isAvailable: Boolean = false - var isSubscribed: Boolean = false +@Parcelize +data class TestingProgram( + var artwork: Artwork = Artwork(), + var displayName: String = String(), + var email: String = String(), + var isAvailable: Boolean = false, + var isSubscribed: Boolean = false, var isSubscribedAndInstalled: Boolean = false -} +) : Parcelable -class TestingProgramStatus { - var subscribed: Boolean = false +@Parcelize +data class TestingProgramStatus( + var subscribed: Boolean = false, var unsubscribed: Boolean = false -} \ No newline at end of file +) : Parcelable diff --git a/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceBundle.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceBundle.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceBundle.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceBundle.kt index 729a28144cea0d0492a5b98620f27194adf009d1..86370867447728a4720fa8f5bcc8e1df6eb4580f 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceBundle.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceBundle.kt @@ -19,4 +19,4 @@ class EditorChoiceBundle { var id: Int = -1 var bundleTitle: String = String() var bundleChoiceClusters: List = ArrayList() -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceCluster.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceCluster.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceCluster.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceCluster.kt index e5fd9590157a64327fee7ddd4d0dc285c562d803..7950ea051a36ce5da291418c9629208f2fb8f007 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceCluster.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceCluster.kt @@ -22,4 +22,4 @@ class EditorChoiceCluster { var clusterTitle: String = String() var clusterBrowseUrl: String = String() var clusterArtwork: List = ArrayList() -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceReason.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceReason.kt similarity index 86% rename from src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceReason.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceReason.kt index 81bfc2679ca5a02028ae5517220175c59ac9e976..829aad3cb70fa48918d4a757b7c7b198239117ae 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceReason.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/editor/EditorChoiceReason.kt @@ -15,4 +15,8 @@ package com.aurora.gplayapi.data.models.editor -data class EditorChoiceReason(var bulletins: List, var description: String) \ No newline at end of file +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class EditorChoiceReason(var bulletins: List, var description: String) : Parcelable diff --git a/src/main/java/com/aurora/gplayapi/data/models/sale/AppOnSale.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/sale/AppOnSale.kt similarity index 69% rename from src/main/java/com/aurora/gplayapi/data/models/sale/AppOnSale.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/sale/AppOnSale.kt index 137b2efc1bf13a795681004308e008a7a815feee..1f33662a8ecdd22caa0a74b4e5520de8040ef06c 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/sale/AppOnSale.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/sale/AppOnSale.kt @@ -16,14 +16,14 @@ package com.aurora.gplayapi.data.models.sale class AppOnSale( - var category: String, - var rating: String, - var id: String, - var idandroid: String, - var downloadsmin: String, - var nameapp: String, - var price: String, - var icon: String, - var oldprice: String, - var dateup: String -) \ No newline at end of file + var category: String, + var rating: String, + var id: String, + var idandroid: String, + var downloadsmin: String, + var nameapp: String, + var price: String, + var icon: String, + var oldprice: String, + var dateup: String +) diff --git a/src/main/java/com/aurora/gplayapi/data/models/sale/SaleBundle.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/sale/SaleBundle.kt similarity index 86% rename from src/main/java/com/aurora/gplayapi/data/models/sale/SaleBundle.kt rename to lib/src/main/java/com/aurora/gplayapi/data/models/sale/SaleBundle.kt index f2054ac45626c276e7344977dcebd44183d25eaf..1887b8df488ffd6bf48b09d1161ee81dee280b7f 100644 --- a/src/main/java/com/aurora/gplayapi/data/models/sale/SaleBundle.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/sale/SaleBundle.kt @@ -16,7 +16,7 @@ package com.aurora.gplayapi.data.models.sale class SaleBundle( - var currency: String, - var currencycode: String, - var sales: List, -) \ No newline at end of file + var currency: String, + var currencycode: String, + var sales: List +) diff --git a/src/main/java/com/aurora/gplayapi/data/providers/BaseDeviceInfoProvider.kt b/lib/src/main/java/com/aurora/gplayapi/data/providers/BaseDeviceInfoProvider.kt similarity index 100% rename from src/main/java/com/aurora/gplayapi/data/providers/BaseDeviceInfoProvider.kt rename to lib/src/main/java/com/aurora/gplayapi/data/providers/BaseDeviceInfoProvider.kt diff --git a/src/main/java/com/aurora/gplayapi/data/providers/DeviceInfoProvider.kt b/lib/src/main/java/com/aurora/gplayapi/data/providers/DeviceInfoProvider.kt similarity index 56% rename from src/main/java/com/aurora/gplayapi/data/providers/DeviceInfoProvider.kt rename to lib/src/main/java/com/aurora/gplayapi/data/providers/DeviceInfoProvider.kt index 59c4cfeae6d7e7092156289813abecc7218f8129..2b1e48004a6943ef41cd85448b70fc0907fdb116 100644 --- a/src/main/java/com/aurora/gplayapi/data/providers/DeviceInfoProvider.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/providers/DeviceInfoProvider.kt @@ -15,10 +15,17 @@ package com.aurora.gplayapi.data.providers -import com.aurora.gplayapi.* -import java.util.* - -class DeviceInfoProvider(var properties: Properties, var localeString: String) : BaseDeviceInfoProvider() { +import com.aurora.gplayapi.AndroidBuildProto +import com.aurora.gplayapi.AndroidCheckinProto +import com.aurora.gplayapi.AndroidCheckinRequest +import com.aurora.gplayapi.DeviceConfigurationProto +import com.aurora.gplayapi.DeviceFeature +import com.aurora.gplayapi.DeviceManager +import java.util.Locale +import java.util.Properties + +class DeviceInfoProvider(var properties: Properties, var localeString: String) : + BaseDeviceInfoProvider() { @Transient private var timeToReport = System.currentTimeMillis() / 1000 @@ -30,7 +37,8 @@ class DeviceInfoProvider(var properties: Properties, var localeString: String) : override val sdkVersion: Int = properties.getProperty("Build.VERSION.SDK_INT").toInt() override val playServicesVersion: Int = properties.getProperty("GSF.version").toInt() override val mccMnc: String = properties.getProperty("SimOperator") - override val authUserAgentString: String = ("GoogleAuth/1.4 (${properties.getProperty("Build.DEVICE")} ${properties.getProperty("Build.ID")})") + override val authUserAgentString: String = + ("GoogleAuth/1.4 (${properties.getProperty("Build.DEVICE")} ${properties.getProperty("Build.ID")})") override val userAgentString: String get() { @@ -47,49 +55,58 @@ class DeviceInfoProvider(var properties: Properties, var localeString: String) : params.add("model=${properties.getProperty("Build.MODEL")}") params.add("buildId=${properties.getProperty("Build.ID")}") params.add("isWideScreen=${0}") - params.add("supportedAbis=${platforms}") + params.add("supportedAbis=$platforms") - return "Android-Finsky/${properties.getProperty("Vending.versionString")} (${params.joinToString(separator = ",")})" + return "Android-Finsky/${properties.getProperty("Vending.versionString")} (${ + params.joinToString( + separator = "," + ) + })" } override fun generateAndroidCheckInRequest(): AndroidCheckinRequest? { return AndroidCheckinRequest.newBuilder() - .setId(0) - .setCheckin( - AndroidCheckinProto.newBuilder() - .setBuild( - AndroidBuildProto.newBuilder() - .setId(properties.getProperty("Build.FINGERPRINT")) - .setProduct(properties.getProperty("Build.HARDWARE")) - .setCarrier(properties.getProperty("Build.BRAND")) - .setRadio(properties.getProperty("Build.RADIO")) - .setBootloader(properties.getProperty("Build.BOOTLOADER")) - .setDevice(properties.getProperty("Build.DEVICE")) - .setSdkVersion(getInt("Build.VERSION.SDK_INT")) - .setModel(properties.getProperty("Build.MODEL")) - .setManufacturer(properties.getProperty("Build.MANUFACTURER")) - .setBuildProduct(properties.getProperty("Build.PRODUCT")) - .setClient(properties.getProperty("Client")) - .setOtaInstalled(java.lang.Boolean.getBoolean(properties.getProperty("OtaInstalled"))) - .setTimestamp(timeToReport) - .setGoogleServices(getInt("GSF.version")) + .setId(0) + .setCheckin( + AndroidCheckinProto.newBuilder() + .setBuild( + AndroidBuildProto.newBuilder() + .setId(properties.getProperty("Build.FINGERPRINT")) + .setProduct(properties.getProperty("Build.HARDWARE")) + .setCarrier(properties.getProperty("Build.BRAND")) + .setRadio(properties.getProperty("Build.RADIO")) + .setBootloader(properties.getProperty("Build.BOOTLOADER")) + .setDevice(properties.getProperty("Build.DEVICE")) + .setSdkVersion(getInt("Build.VERSION.SDK_INT")) + .setModel(properties.getProperty("Build.MODEL")) + .setManufacturer(properties.getProperty("Build.MANUFACTURER")) + .setBuildProduct(properties.getProperty("Build.PRODUCT")) + .setClient(properties.getProperty("Client")) + .setOtaInstalled( + java.lang.Boolean.parseBoolean( + properties.getProperty("OtaInstalled", "false") ) - .setLastCheckinMsec(0) - .setCellOperator(properties.getProperty("CellOperator")) - .setSimOperator(properties.getProperty("SimOperator")) - .setRoaming(properties.getProperty("Roaming")) - .setUserNumber(0) - ) - .setLocale(localeString) - .setTimeZone(properties.getProperty("TimeZone")) - .setVersion(3) - .setDeviceConfiguration(deviceConfigurationProto) - .setFragment(0) - .build() + ) + .setTimestamp(timeToReport) + .setGoogleServices(getInt("GSF.version")) + ) + .setLastCheckinMsec(0) + .setCellOperator(properties.getProperty("CellOperator")) + .setSimOperator(properties.getProperty("SimOperator")) + .setRoaming(properties.getProperty("Roaming")) + .setUserNumber(0) + ) + .setLocale(localeString) + .setTimeZone(properties.getProperty("TimeZone")) + .setVersion(3) + .setDeviceConfiguration(deviceConfigurationProto) + .setFragment(0) + .build() } @Transient - override val deviceConfigurationProto: DeviceConfigurationProto = DeviceConfigurationProto.newBuilder() + override val deviceConfigurationProto: DeviceConfigurationProto = + DeviceConfigurationProto.newBuilder() .setTouchScreen(getInt("TouchScreen")) .setKeyboard(getInt("Keyboard")) .setNavigation(getInt("Navigation")) @@ -121,15 +138,15 @@ class DeviceInfoProvider(var properties: Properties, var localeString: String) : } private fun getList(key: String): List { - return listOf(*properties.getProperty(key).split(",".toRegex()).toTypedArray()) + return listOf(*properties.getProperty(key, "").split(",".toRegex()).toTypedArray()) } private fun getDeviceFeatures(): List { return getList("Features").map { DeviceFeature.newBuilder() - .setName(it) - .setValue(0) - .build() + .setName(it) + .setValue(0) + .build() } } @@ -137,14 +154,22 @@ class DeviceInfoProvider(var properties: Properties, var localeString: String) : if (!properties.containsKey("Vending.versionString") && properties.containsKey("Vending.version")) { var vendingVersionString = "7.1.15" if (properties.getProperty("Vending.version").length > 6) { - vendingVersionString = StringBuilder(properties.getProperty("Vending.version").substring(2, 6)).insert(2, ".").insert(1, ".").toString() + vendingVersionString = + StringBuilder(properties.getProperty("Vending.version").substring(2, 6)).insert( + 2, + "." + ).insert(1, ".").toString() } properties["Vending.versionString"] = vendingVersionString } - if (properties.containsKey("Build.FINGERPRINT") && (!properties.containsKey("Build.ID") - || !properties.containsKey("Build.VERSION.RELEASE"))) { - val fingerprint = properties.getProperty("Build.FINGERPRINT").split("/".toRegex()).toTypedArray() + if (properties.containsKey("Build.FINGERPRINT") && ( + !properties.containsKey("Build.ID") || + !properties.containsKey("Build.VERSION.RELEASE") + ) + ) { + val fingerprint = + properties.getProperty("Build.FINGERPRINT").split("/".toRegex()).toTypedArray() var buildId = "" var release = "" @@ -174,39 +199,39 @@ class DeviceInfoProvider(var properties: Properties, var localeString: String) : companion object { @Transient private val requiredFields = arrayOf( - "UserReadableName", - "Build.HARDWARE", - "Build.RADIO", - "Build.BOOTLOADER", - "Build.FINGERPRINT", - "Build.BRAND", - "Build.DEVICE", - "Build.VERSION.SDK_INT", - "Build.MODEL", - "Build.MANUFACTURER", - "Build.PRODUCT", - "TouchScreen", - "Keyboard", - "Navigation", - "ScreenLayout", - "HasHardKeyboard", - "HasFiveWayNavigation", - "GL.Version", - "GSF.version", - "Vending.version", - "Screen.Density", - "Screen.Width", - "Screen.Height", - "Platforms", - "SharedLibraries", - "Features", - "Locales", - "CellOperator", - "SimOperator", - "Roaming", - "Client", - "TimeZone", - "GL.Extensions" + "UserReadableName", + "Build.HARDWARE", + "Build.RADIO", + "Build.BOOTLOADER", + "Build.FINGERPRINT", + "Build.BRAND", + "Build.DEVICE", + "Build.VERSION.SDK_INT", + "Build.MODEL", + "Build.MANUFACTURER", + "Build.PRODUCT", + "TouchScreen", + "Keyboard", + "Navigation", + "ScreenLayout", + "HasHardKeyboard", + "HasFiveWayNavigation", + "GL.Version", + "GSF.version", + "Vending.version", + "Screen.Density", + "Screen.Width", + "Screen.Height", + "Platforms", + "SharedLibraries", + "Features", + "Locales", + "CellOperator", + "SimOperator", + "Roaming", + "Client", + "TimeZone", + "GL.Extensions" ) fun getDefault(): DeviceInfoProvider? { @@ -216,4 +241,4 @@ class DeviceInfoProvider(var properties: Properties, var localeString: String) : return DeviceInfoProvider(properties, Locale.getDefault().toString()) } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/providers/HeaderProvider.kt b/lib/src/main/java/com/aurora/gplayapi/data/providers/HeaderProvider.kt similarity index 96% rename from src/main/java/com/aurora/gplayapi/data/providers/HeaderProvider.kt rename to lib/src/main/java/com/aurora/gplayapi/data/providers/HeaderProvider.kt index bec12e5732728a8484d8d9e58a107d27e963137c..ae3ec92620f548a6a0f64f3c2fc3a704a877317d 100644 --- a/src/main/java/com/aurora/gplayapi/data/providers/HeaderProvider.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/providers/HeaderProvider.kt @@ -16,7 +16,7 @@ package com.aurora.gplayapi.data.providers import com.aurora.gplayapi.data.models.AuthData -import java.util.* +import java.util.Locale object HeaderProvider { @@ -24,8 +24,9 @@ object HeaderProvider { val headers: MutableMap = HashMap() headers["app"] = "com.google.android.gms" headers["User-Agent"] = builder.deviceInfoProvider!!.authUserAgentString - if (builder.gsfId.isNotBlank()) + if (builder.gsfId.isNotBlank()) { headers["device"] = builder.gsfId + } return headers } @@ -43,12 +44,13 @@ object HeaderProvider { headers["X-DFE-Network-Type"] = "4" headers["X-DFE-Content-Filters"] = "" headers["X-Limit-Ad-Tracking-Enabled"] = "false" - headers["X-Ad-Id"] = "LawadaMera" + headers["X-Ad-Id"] = "" headers["X-DFE-UserLanguages"] = authData.locale.toString() headers["X-DFE-Request-Params"] = "timeoutMs=4000" if (authData.deviceCheckInConsistencyToken.isNotBlank()) { - headers["X-DFE-Device-Checkin-Consistency-Token"] = authData.deviceCheckInConsistencyToken + headers["X-DFE-Device-Checkin-Consistency-Token"] = + authData.deviceCheckInConsistencyToken } if (authData.deviceConfigToken.isNotBlank()) { @@ -85,7 +87,7 @@ object HeaderProvider { headers["X-DFE-Network-Type"] = "4" headers["X-DFE-Content-Filters"] = "" headers["X-Limit-Ad-Tracking-Enabled"] = "false" - headers["X-Ad-Id"] = "LawadaMera" + headers["X-Ad-Id"] = "" headers["X-DFE-UserLanguages"] = locale.toString() headers["X-DFE-Request-Params"] = "timeoutMs=4000" @@ -95,4 +97,4 @@ object HeaderProvider { } return headers } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/data/providers/ParamProvider.kt b/lib/src/main/java/com/aurora/gplayapi/data/providers/ParamProvider.kt similarity index 84% rename from src/main/java/com/aurora/gplayapi/data/providers/ParamProvider.kt rename to lib/src/main/java/com/aurora/gplayapi/data/providers/ParamProvider.kt index 0af91c19060796d8dd3e2faee91a6839e80ecd21..bef05b5174a8780782e0dabfed09a9465bf11f5c 100644 --- a/src/main/java/com/aurora/gplayapi/data/providers/ParamProvider.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/providers/ParamProvider.kt @@ -16,19 +16,21 @@ package com.aurora.gplayapi.data.providers import com.aurora.gplayapi.data.models.AuthData -import java.util.* +import java.util.Locale object ParamProvider { fun getDefaultAuthParams(builder: AuthData): Map { val params: MutableMap = HashMap() - if (builder.gsfId.isNotBlank()) + if (builder.gsfId.isNotBlank()) { params["androidId"] = builder.gsfId + } params["sdk_version"] = builder.deviceInfoProvider!!.sdkVersion.toString() params["Email"] = builder.email - params["google_play_services_version"] = builder.deviceInfoProvider!!.playServicesVersion.toString() - params["device_country"] = builder.locale.country.toLowerCase() - params["lang"] = builder.locale.language.toLowerCase() + params["google_play_services_version"] = + builder.deviceInfoProvider!!.playServicesVersion.toString() + params["device_country"] = builder.locale.country.lowercase(Locale.getDefault()) + params["lang"] = builder.locale.language.lowercase(Locale.getDefault()) params["callerSig"] = "38918a453d07199354f8b19af05ec6562ced5788" return params } @@ -56,4 +58,4 @@ object ParamProvider { params["Token"] = oauthToken return params } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/exceptions/ApiException.kt b/lib/src/main/java/com/aurora/gplayapi/exceptions/ApiException.kt similarity index 84% rename from src/main/java/com/aurora/gplayapi/exceptions/ApiException.kt rename to lib/src/main/java/com/aurora/gplayapi/exceptions/ApiException.kt index 48a580b581128981266b645dbc55f074f8a06977..e5ff2c5dede672648138b7f7d7cc9aead1b40514 100644 --- a/src/main/java/com/aurora/gplayapi/exceptions/ApiException.kt +++ b/lib/src/main/java/com/aurora/gplayapi/exceptions/ApiException.kt @@ -15,19 +15,21 @@ package com.aurora.gplayapi.exceptions -import java.lang.Exception - sealed class ApiException { data class AppNotPurchased(val reason: String = "App not purchased") : Exception() - data class AppNotFound(val reason: String = "App not found, maybe restricted (OEM or Geo)") : Exception() + data class AppNotFound(val reason: String = "App not found, maybe restricted (OEM or Geo)") : + Exception() + + data class AppRemoved(val reason: String = "App removed from Play Store") : Exception() data class AppNotSupported(val reason: String = "App not supported") : Exception() - data class EmptyDownloads(val reason: String = "File list empty") : Exception() //Not sure about the root cause. + data class EmptyDownloads(val reason: String = "File list empty") : + Exception() // Not sure about the root cause. data class Unknown(val reason: String = "¯\\_(ツ)_/¯") : Exception() data class Server(val code: Int = 500, val reason: String = "Server error") : Exception() -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/exceptions/AuthException.kt b/lib/src/main/java/com/aurora/gplayapi/exceptions/AuthException.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/exceptions/AuthException.kt rename to lib/src/main/java/com/aurora/gplayapi/exceptions/AuthException.kt index 7eeb0c3c89c73b4328b30a86b325e9ce4f3482bc..7988b984a3da9ec50572bf92b653222c55f19c04 100644 --- a/src/main/java/com/aurora/gplayapi/exceptions/AuthException.kt +++ b/lib/src/main/java/com/aurora/gplayapi/exceptions/AuthException.kt @@ -20,4 +20,4 @@ import java.io.IOException class AuthException(message: String?) : IOException(message) { var code = 0 var rawResponse: String = String() -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/exceptions/GooglePlayException.kt b/lib/src/main/java/com/aurora/gplayapi/exceptions/GooglePlayException.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/exceptions/GooglePlayException.kt rename to lib/src/main/java/com/aurora/gplayapi/exceptions/GooglePlayException.kt index cde0119c46cc5aa92ded951be229fdbf179d5053..f9e96b51550aa5803491acd553ab3440e3afbffa 100644 --- a/src/main/java/com/aurora/gplayapi/exceptions/GooglePlayException.kt +++ b/lib/src/main/java/com/aurora/gplayapi/exceptions/GooglePlayException.kt @@ -20,4 +20,4 @@ import java.io.IOException class GooglePlayException(message: String?) : IOException(message) { var code = 0 var rawResponse: String = String() -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/AppDetailsHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/AppDetailsHelper.kt similarity index 83% rename from src/main/java/com/aurora/gplayapi/helpers/AppDetailsHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/AppDetailsHelper.kt index a544c359ac20b2581908b406cc6b856cde0f4306..0143ed93ef6471228ed482c0a8c9cadbc9369875 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/AppDetailsHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/AppDetailsHelper.kt @@ -15,6 +15,7 @@ package com.aurora.gplayapi.helpers +import com.aurora.gplayapi.DetailsResponse import com.aurora.gplayapi.GooglePlayApi import com.aurora.gplayapi.ListResponse import com.aurora.gplayapi.Payload @@ -29,8 +30,6 @@ import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders import com.aurora.gplayapi.exceptions.ApiException import com.aurora.gplayapi.network.IHttpClient import java.io.IOException -import java.util.* - class AppDetailsHelper(authData: AuthData) : BaseHelper(authData) { @@ -60,10 +59,12 @@ class AppDetailsHelper(authData: AuthData) : BaseHelper(authData) { if (subItem.hasAnnotations() && subItem.annotations.hasOverlayMetaData()) { if (subItem.annotations.overlayMetaData.hasOverlayTitle()) { devStream.title = subItem.annotations.overlayMetaData.overlayTitle.title - devStream.imgUrl = subItem.annotations.overlayMetaData.overlayTitle.compositeImage.url + devStream.imgUrl = + subItem.annotations.overlayMetaData.overlayTitle.compositeImage.url } if (subItem.annotations.overlayMetaData.hasOverlayDescription()) { - devStream.description = subItem.annotations.overlayMetaData.overlayDescription.description + devStream.description = + subItem.annotations.overlayMetaData.overlayDescription.description } } } @@ -73,23 +74,31 @@ class AppDetailsHelper(authData: AuthData) : BaseHelper(authData) { } @Throws(Exception::class) - fun getAppByPackageName(packageName: String): App { + fun getDetailsResponseByPackageName(packageName: String): DetailsResponse { val headers: Map = getDefaultHeaders(authData) val params: MutableMap = HashMap() params["doc"] = packageName val playResponse = httpClient.get(GooglePlayApi.URL_DETAILS, headers, params) - if (playResponse.isSuccessful) { - val detailsResponse = getDetailsResponseFromBytes(playResponse.responseBytes) - return AppBuilder.build(detailsResponse) + return getDetailsResponseFromBytes(playResponse.responseBytes) } else { throw ApiException.AppNotFound(playResponse.errorString) } } + @Throws(Exception::class) + fun getAppByPackageName(packageName: String): App { + val detailsResponse = getDetailsResponseByPackageName(packageName) + return AppBuilder.build(detailsResponse) + } + @Throws(Exception::class) fun getAppByPackageName(packageList: List): List { + if (packageList.isEmpty()) { + return emptyList() + } + val appList: MutableList = ArrayList() val headers: MutableMap = getDefaultHeaders(authData) val request = getBulkDetailsBytes(packageList) @@ -106,13 +115,14 @@ class AppDetailsHelper(authData: AuthData) : BaseHelper(authData) { val bulkDetailsResponse = payload.bulkDetailsResponse for (entry in bulkDetailsResponse.entryList) { val app = AppBuilder.build(entry.item) - //System.out.printf("%s -> %s\n", app.displayName, app.packageName); + // System.out.printf("%s -> %s\n", app.displayName, app.packageName); appList.add(app) } } return appList - } else + } else { throw ApiException.Server(playResponse.code, playResponse.errorString) + } } fun getDetailsStream(streamUrl: String): StreamBundle { @@ -120,7 +130,7 @@ class AppDetailsHelper(authData: AuthData) : BaseHelper(authData) { val params: MutableMap = HashMap() val playResponse = httpClient.get( - "${GooglePlayApi.URL_FDFE}/${streamUrl}", + "${GooglePlayApi.URL_FDFE}/$streamUrl", headers, params ) @@ -171,19 +181,21 @@ class AppDetailsHelper(authData: AuthData) : BaseHelper(authData) { val payload = getPayLoadFromBytes(playResponse.responseBytes) payload.hasTestingProgramResponse() TestingProgramStatus().apply { - if (payload.hasTestingProgramResponse() - && payload.testingProgramResponse.hasResult() - && payload.testingProgramResponse.result.hasDetails() + if (payload.hasTestingProgramResponse() && + payload.testingProgramResponse.hasResult() && + payload.testingProgramResponse.result.hasDetails() ) { val details = payload.testingProgramResponse.result.details - if (details.hasSubscribed()) + if (details.hasSubscribed()) { subscribed = details.subscribed - if (details.hasUnsubscribed()) + } + if (details.hasUnsubscribed()) { unsubscribed = details.unsubscribed + } } } } else { TestingProgramStatus() } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/AppSalesHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/AppSalesHelper.kt similarity index 87% rename from src/main/java/com/aurora/gplayapi/helpers/AppSalesHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/AppSalesHelper.kt index 9e425655fc58b72a97ca9eedb2773484a2c18116..97de6c34aa955e3df98da095a2ff61664dda1825 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/AppSalesHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/AppSalesHelper.kt @@ -22,7 +22,7 @@ import com.aurora.gplayapi.data.models.sale.SaleBundle import com.aurora.gplayapi.network.IHttpClient import com.google.gson.Gson import java.io.IOException -import java.util.* +import java.util.Locale class AppSalesHelper(authData: AuthData) : BaseHelper(authData) { @@ -43,11 +43,14 @@ class AppSalesHelper(authData: AuthData) : BaseHelper(authData) { val playResponse = httpClient.get(GooglePlayApi.SALES_URL, headers = mapOf(), params) val saleBundle = Gson().fromJson(String(playResponse.responseBytes), SaleBundle::class.java) - return if (saleBundle.sales.isEmpty()) + return if (saleBundle.sales.isEmpty()) { listOf() - else { + } else { val appDetailsHelper = AppDetailsHelper(authData) - return appDetailsHelper.getAppByPackageName(packageList = saleBundle.sales.map { it.idandroid }.toList()) + return appDetailsHelper.getAppByPackageName( + packageList = saleBundle.sales.map { it.idandroid } + .toList() + ) } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/AuthHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/AuthHelper.kt similarity index 84% rename from src/main/java/com/aurora/gplayapi/helpers/AuthHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/AuthHelper.kt index f7d7404a3304fed991a5edbb90708b192d2331f7..c38fd28e082c9f363cca3e96bd5b291f54f7cf63 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/AuthHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/AuthHelper.kt @@ -21,7 +21,8 @@ import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.providers.DeviceInfoProvider import com.aurora.gplayapi.network.DefaultHttpClient import com.aurora.gplayapi.network.IHttpClient -import java.util.* +import java.util.Locale +import java.util.Properties class AuthHelper private constructor() { @@ -35,26 +36,28 @@ class AuthHelper private constructor() { fun build(email: String, aasToken: String): AuthData { val properties = DeviceManager.loadProperties("px_3a.properties") - if (properties != null) + if (properties != null) { return build(email, aasToken, properties) - else + } else { throw Exception("Unable to read device config") + } } fun build(email: String, aasToken: String, deviceName: String): AuthData { val properties = DeviceManager.loadProperties(deviceName) - if (properties != null) + if (properties != null) { return build(email, aasToken, properties) - else + } else { throw Exception("Unable to read device config") + } } - fun build(email: String, aasToken: String, properties: Properties): AuthData { - val deviceInfoProvider = DeviceInfoProvider(properties, Locale.getDefault().toString()) + fun build(email: String, aasToken: String, properties: Properties, locale: Locale = Locale.getDefault()): AuthData { + val deviceInfoProvider = DeviceInfoProvider(properties, locale.toString()) val authData = AuthData(email, aasToken) authData.deviceInfoProvider = deviceInfoProvider - authData.locale = Locale.getDefault() + authData.locale = locale val api = GooglePlayApi(authData).via(httpClient) val gsfId = api.generateGsfId(deviceInfoProvider) @@ -63,18 +66,12 @@ class AuthHelper private constructor() { val deviceConfigResponse = api.uploadDeviceConfig(deviceInfoProvider) authData.deviceConfigToken = deviceConfigResponse.uploadDeviceConfigToken - val ac2dm = api.generateToken(aasToken, GooglePlayApi.Service.AC2DM) - authData.ac2dmToken = ac2dm - - val gcmToken = api.generateToken(aasToken, GooglePlayApi.Service.GCM) - authData.gcmToken = gcmToken - val token = api.generateToken(aasToken, GooglePlayApi.Service.GOOGLE_PLAY) authData.authToken = token val tosResponse = api.toc() - //Fetch UserProfile + // Fetch UserProfile authData.userProfile = UserProfileHelper(authData).getUserProfile() return authData @@ -86,7 +83,6 @@ class AuthHelper private constructor() { locale: Locale, deviceInfoProvider: DeviceInfoProvider ): AuthData { - val authData = AuthData(email, authToken, true) authData.deviceInfoProvider = deviceInfoProvider @@ -94,21 +90,21 @@ class AuthHelper private constructor() { val api = GooglePlayApi(authData) - //Android GSF ID + // Android GSF ID val gsfId = api.generateGsfId(deviceInfoProvider) authData.gsfId = gsfId - //Upload Device Config + // Upload Device Config val deviceConfigResponse = api.uploadDeviceConfig(deviceInfoProvider) authData.deviceConfigToken = deviceConfigResponse.uploadDeviceConfigToken - //GooglePlay TOS + // GooglePlay TOS val tosResponse = api.toc() - //Fetch UserProfile + // Fetch UserProfile authData.userProfile = UserProfileHelper(authData).getUserProfile() return authData } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/AuthValidator.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/AuthValidator.kt similarity index 62% rename from src/main/java/com/aurora/gplayapi/helpers/AuthValidator.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/AuthValidator.kt index cd05d246e69729842303f897761a53036ecaee2a..76f4093832a59253f5ed3da59e3f0fc51a601bc8 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/AuthValidator.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/AuthValidator.kt @@ -15,9 +15,7 @@ package com.aurora.gplayapi.helpers -import com.aurora.gplayapi.GooglePlayApi import com.aurora.gplayapi.data.models.AuthData -import com.aurora.gplayapi.data.providers.HeaderProvider import com.aurora.gplayapi.network.IHttpClient class AuthValidator(authData: AuthData) : BaseHelper(authData) { @@ -26,18 +24,16 @@ class AuthValidator(authData: AuthData) : BaseHelper(authData) { this.httpClient = httpClient } - fun isValid(endpoint: String = GooglePlayApi.URL_SYNC, method: METHOD = METHOD.POST): Boolean { - val headers = HeaderProvider.getDefaultHeaders(authData) - val playResponse = when (method) { - METHOD.POST -> httpClient.post(endpoint, headers, hashMapOf()) - METHOD.GET -> httpClient.get(endpoint, headers, hashMapOf()) - } - - return playResponse.isSuccessful - } + fun isValid(): Boolean { + return try { + val testPackageName = "com.android.chrome" + val app = AppDetailsHelper(authData) + .using(httpClient) + .getAppByPackageName(testPackageName) - enum class METHOD { - GET, - POST + app.packageName == testPackageName + } catch (e: Exception) { + false + } } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/BaseHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/BaseHelper.kt similarity index 83% rename from src/main/java/com/aurora/gplayapi/helpers/BaseHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/BaseHelper.kt index 02d40014c7e9469983b8a8e304b1079d4fc5e660..375152d265b099eec899cfcf52b4f79f2a212f68 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/BaseHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/BaseHelper.kt @@ -15,16 +15,31 @@ package com.aurora.gplayapi.helpers -import com.aurora.gplayapi.* +import com.aurora.gplayapi.BrowseResponse +import com.aurora.gplayapi.BulkDetailsRequest +import com.aurora.gplayapi.DetailsResponse +import com.aurora.gplayapi.GooglePlayApi +import com.aurora.gplayapi.Item +import com.aurora.gplayapi.ListResponse +import com.aurora.gplayapi.Payload +import com.aurora.gplayapi.PayloadApi +import com.aurora.gplayapi.ResponseWrapper +import com.aurora.gplayapi.ResponseWrapperApi +import com.aurora.gplayapi.SearchResponse +import com.aurora.gplayapi.SearchSuggestResponse import com.aurora.gplayapi.data.builders.AppBuilder.build -import com.aurora.gplayapi.data.models.* +import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.data.models.Artwork +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.PlayResponse +import com.aurora.gplayapi.data.models.StreamBundle +import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.data.models.editor.EditorChoiceBundle import com.aurora.gplayapi.data.models.editor.EditorChoiceCluster import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders import com.aurora.gplayapi.network.DefaultHttpClient import com.aurora.gplayapi.network.IHttpClient import java.io.IOException -import java.util.* abstract class BaseHelper(protected var authData: AuthData) { @@ -33,7 +48,11 @@ abstract class BaseHelper(protected var authData: AuthData) { abstract fun using(httpClient: IHttpClient): BaseHelper @Throws(IOException::class) - fun getResponse(url: String, params: Map, headers: Map): PlayResponse { + fun getResponse( + url: String, + params: Map, + headers: Map + ): PlayResponse { return httpClient.get(url, headers, params) } @@ -80,13 +99,19 @@ abstract class BaseHelper(protected var authData: AuthData) { fun getPrefetchPayLoad(bytes: ByteArray?): Payload { val responseWrapper = ResponseWrapper.parseFrom(bytes) val payload = responseWrapper.payload - return if (responseWrapper.preFetchCount > 0 && ((payload.hasSearchResponse() - && payload.searchResponse.itemCount == 0) - || payload.hasListResponse() && payload.listResponse.itemCount == 0 - || payload.hasBrowseResponse()) + return if (responseWrapper.preFetchCount > 0 && ( + ( + payload.hasSearchResponse() && + payload.searchResponse.itemCount == 0 + ) || + payload.hasListResponse() && payload.listResponse.itemCount == 0 || + payload.hasBrowseResponse() + ) ) { responseWrapper.getPreFetch(0).response.payload - } else payload + } else { + payload + } } open fun getAppsFromItem(item: Item): MutableList { @@ -96,7 +121,7 @@ abstract class BaseHelper(protected var authData: AuthData) { if (subItem.type == 1) { val app = build(subItem) appList.add(app) - //System.out.printf("%s -> %s\n", app.displayName, app.packageName); + // System.out.printf("%s -> %s\n", app.displayName, app.packageName); } } } @@ -115,7 +140,9 @@ abstract class BaseHelper(protected var authData: AuthData) { val payload = getPayLoadFromBytes(bytes) return if (payload.hasSearchResponse()) { payload.searchResponse - } else null + } else { + null + } } @Throws(Exception::class) @@ -123,7 +150,9 @@ abstract class BaseHelper(protected var authData: AuthData) { val payload = getPayLoadFromBytes(bytes) return if (payload.hasSearchSuggestResponse()) { payload.searchSuggestResponse - } else null + } else { + null + } } /*--------------------------------------- GENERIC APP STREAMS --------------------------------------------*/ @@ -131,20 +160,22 @@ abstract class BaseHelper(protected var authData: AuthData) { fun getNextStreamResponse(nextPageUrl: String): ListResponse { val headers: Map = getDefaultHeaders(authData) val playResponse = httpClient.get(GooglePlayApi.URL_FDFE + "/" + nextPageUrl, headers) - return if (playResponse.isSuccessful) + return if (playResponse.isSuccessful) { getListResponseFromBytes(playResponse.responseBytes) - else + } else { ListResponse.getDefaultInstance() + } } @Throws(Exception::class) fun getBrowseStreamResponse(browseUrl: String): BrowseResponse { val headers: Map = getDefaultHeaders(authData) val playResponse = httpClient.get(GooglePlayApi.URL_FDFE + "/" + browseUrl, headers) - return if (playResponse.isSuccessful) + return if (playResponse.isSuccessful) { getBrowseResponseFromBytes(playResponse.responseBytes) - else + } else { BrowseResponse.getDefaultInstance() + } } @Throws(Exception::class) @@ -169,9 +200,11 @@ abstract class BaseHelper(protected var authData: AuthData) { } fun getStreamCluster(payload: Payload): StreamCluster { - return if (payload.hasListResponse()) + return if (payload.hasListResponse()) { getStreamCluster(payload.listResponse) - else StreamCluster() + } else { + StreamCluster() + } } fun getStreamCluster(listResponse: ListResponse): StreamCluster { @@ -261,13 +294,15 @@ abstract class BaseHelper(protected var authData: AuthData) { val browseUrl = getBrowseUrl(item) if (item.imageCount > 0) { item.imageList.forEach { - artworkList.add(Artwork().apply { - type = it.imageType - url = it.imageUrl - aspectRatio = it.dimension.aspectRatio - width = it.dimension.width - height = it.dimension.height - }) + artworkList.add( + Artwork().apply { + type = it.imageType + url = it.imageUrl + aspectRatio = it.dimension.aspectRatio + width = it.dimension.width + height = it.dimension.height + } + ) } } return EditorChoiceCluster().apply { @@ -312,4 +347,4 @@ abstract class BaseHelper(protected var authData: AuthData) { return editorChoiceBundles } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/CategoryAppsHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/CategoryAppsHelper.kt similarity index 100% rename from src/main/java/com/aurora/gplayapi/helpers/CategoryAppsHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/CategoryAppsHelper.kt diff --git a/src/main/java/com/aurora/gplayapi/helpers/CategoryHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/CategoryHelper.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/helpers/CategoryHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/CategoryHelper.kt index 95609d42595718218e8ac7f27ea02fcc722b23f4..7830968511a46d22845e04de1500502511e5935b 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/CategoryHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/CategoryHelper.kt @@ -22,7 +22,6 @@ import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.providers.HeaderProvider import com.aurora.gplayapi.network.IHttpClient -import java.util.* class CategoryHelper(authData: AuthData) : BaseHelper(authData) { @@ -71,4 +70,4 @@ class CategoryHelper(authData: AuthData) : BaseHelper(authData) { category.type = type return category } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/Chart.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/Chart.kt similarity index 100% rename from src/main/java/com/aurora/gplayapi/helpers/Chart.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/Chart.kt diff --git a/src/main/java/com/aurora/gplayapi/helpers/ClusterHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/ClusterHelper.kt similarity index 98% rename from src/main/java/com/aurora/gplayapi/helpers/ClusterHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/ClusterHelper.kt index 2b1f506fac7fa87f0cac1627e2224d54c112ee69..b8b7eaa01bce968ea91acf6a82221215933569fa 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/ClusterHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/ClusterHelper.kt @@ -20,7 +20,6 @@ import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders import com.aurora.gplayapi.network.IHttpClient -import java.util.* class ClusterHelper(authData: AuthData) : BaseHelper(authData) { @@ -46,8 +45,9 @@ class ClusterHelper(authData: AuthData) : BaseHelper(authData) { return if (responseBody.isSuccessful) { val listResponse = getListResponseFromBytes(responseBody.responseBytes) getStreamCluster(listResponse) - } else + } else { StreamCluster() + } } enum class Type(var value: String) { @@ -55,4 +55,4 @@ class ClusterHelper(authData: AuthData) : BaseHelper(authData) { MY_APPS_LIBRARY("LIBRARY"), MY_APPS_UPDATES("UPDATES"); } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/ExpandedBrowseHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/ExpandedBrowseHelper.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/helpers/ExpandedBrowseHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/ExpandedBrowseHelper.kt index 5c4c238d8843df6fc5666bb5678c3aa25abf8160..1efe9d2bc10cec441b0cc7413b3569cfcc24ba92 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/ExpandedBrowseHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/ExpandedBrowseHelper.kt @@ -61,4 +61,4 @@ class ExpandedBrowseHelper(authData: AuthData) : BaseHelper(authData) { } return appList } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/LibraryHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/LibraryHelper.kt similarity index 86% rename from src/main/java/com/aurora/gplayapi/helpers/LibraryHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/LibraryHelper.kt index a4286642902cfe3468bc2bdcb296d2b53b7db4e8..642f4c88a1d7b0a24083a189bcf3faef2b5aa6eb 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/LibraryHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/LibraryHelper.kt @@ -15,7 +15,9 @@ package com.aurora.gplayapi.helpers -import com.aurora.gplayapi.* +import com.aurora.gplayapi.GooglePlayApi +import com.aurora.gplayapi.ListResponse +import com.aurora.gplayapi.ModifyLibraryRequest import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders @@ -57,12 +59,17 @@ class LibraryHelper(authData: AuthData) : BaseHelper(authData) { val builder = ModifyLibraryRequest.newBuilder() .setLibraryId("u-wl") - if (isAddRequest) + if (isAddRequest) { builder.addAddPackageName(packageName) - else + } else { builder.addRemovePackageName(packageName) + } - val playResponse = httpClient.post(GooglePlayApi.URL_MODIFY_LIBRARY, headers, builder.build().toByteArray()) + val playResponse = httpClient.post( + GooglePlayApi.URL_MODIFY_LIBRARY, + headers, + builder.build().toByteArray() + ) return playResponse.isSuccessful } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/PurchaseHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/PurchaseHelper.kt similarity index 60% rename from src/main/java/com/aurora/gplayapi/helpers/PurchaseHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/PurchaseHelper.kt index 56e7035f8d0d27cbaeb73d95d3a717c4a343f4f3..1cc3277e94663542403553979180a3dfe691d2db 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/PurchaseHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/PurchaseHelper.kt @@ -15,16 +15,20 @@ package com.aurora.gplayapi.helpers -import com.aurora.gplayapi.* +import com.aurora.gplayapi.BuyResponse import com.aurora.gplayapi.Constants.PATCH_FORMAT +import com.aurora.gplayapi.DeliveryResponse +import com.aurora.gplayapi.GooglePlayApi +import com.aurora.gplayapi.ListResponse +import com.aurora.gplayapi.ResponseWrapper import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.File import com.aurora.gplayapi.data.providers.HeaderProvider import com.aurora.gplayapi.exceptions.ApiException import com.aurora.gplayapi.network.IHttpClient +import com.aurora.gplayapi.utils.CertUtil import java.io.IOException -import java.util.* class PurchaseHelper(authData: AuthData) : BaseHelper(authData) { @@ -32,7 +36,15 @@ class PurchaseHelper(authData: AuthData) : BaseHelper(authData) { this.httpClient = httpClient } - fun getPurchaseHistory(offset: Int = 0): List { + /** + * @param offset + * @param getAllAppDetails + * false: the returned App instances will only contain basic properties + * true: all App details are retrieved using AppDetailsHelper + * @return list of apps purchased by the selected account, starting at offset. + * The number of entries is defined by Google (usually less than 20) + */ + fun getPurchaseHistory(offset: Int = 0, getAllAppDetails: Boolean = true): List { val headers: MutableMap = HeaderProvider.getDefaultHeaders(authData) val params: MutableMap = mutableMapOf( "o" to "$offset" @@ -49,18 +61,49 @@ class PurchaseHelper(authData: AuthData) : BaseHelper(authData) { for (item in listResponse.itemList) { for (subItem in item.subItemList) { if (item.subItemCount > 0) { - if (item.hasAnnotations() - && item.annotations.hasPurchaseHistoryDetails() - && item.annotations.purchaseHistoryDetails.hasPurchaseStatus() - ) + if (item.hasAnnotations() && + item.annotations.hasPurchaseHistoryDetails() && + item.annotations.purchaseHistoryDetails.hasPurchaseStatus() + ) { continue + } purchaseAppList.addAll(getAppsFromItem(subItem)) } } } } + if (!getAllAppDetails) { + return purchaseAppList + } + return AppDetailsHelper(authData).getAppByPackageName( + purchaseAppList.map { it.packageName } + .distinct() + ) + } + + @Throws(IOException::class) + fun getDeliveryToken(packageName: String, versionCode: Int, offerType: Int, certificateHash: String): String { + val params: MutableMap = HashMap() + params["ot"] = offerType.toString() + params["doc"] = packageName + params["vc"] = versionCode.toString() + + if (certificateHash.isNotEmpty()) { + params["ch"] = certificateHash + } + + val playResponse = httpClient.post( + GooglePlayApi.PURCHASE_URL, + HeaderProvider.getDefaultHeaders(authData), + params + ) - return AppDetailsHelper(authData).getAppByPackageName(purchaseAppList.map { it.packageName }) + return if (playResponse.isSuccessful) { + val payload = getPayLoadFromBytes(playResponse.responseBytes) + payload.buyResponse.encodedDeliveryToken + } else { + "" + } } @Throws(IOException::class) @@ -95,9 +138,9 @@ class PurchaseHelper(authData: AuthData) : BaseHelper(authData) { PATCH_FORMAT.GZIPPED_GDIFF, PATCH_FORMAT.GZIPPED_BSDIFF ), - downloadToken: String + deliveryToken: String, + certificateHash: String ): DeliveryResponse { - val params: MutableMap = HashMap() params["ot"] = offerType.toString() params["doc"] = packageName @@ -108,12 +151,20 @@ class PurchaseHelper(authData: AuthData) : BaseHelper(authData) { params["pf"] = patchFormats[0].value.toString(); }*/ - if (downloadToken.isNotEmpty()) { - params["dtok"] = downloadToken + if (certificateHash.isNotEmpty()) { + params["ch"] = certificateHash + } + + if (deliveryToken.isNotEmpty()) { + params["dtok"] = deliveryToken } val playResponse = - httpClient.get(GooglePlayApi.DELIVERY_URL, HeaderProvider.getDefaultHeaders(authData), params) + httpClient.get( + GooglePlayApi.DELIVERY_URL, + HeaderProvider.getDefaultHeaders(authData), + params + ) val payload = ResponseWrapper.parseFrom(playResponse.responseBytes).payload return payload.deliveryResponse } @@ -169,22 +220,32 @@ class PurchaseHelper(authData: AuthData) : BaseHelper(authData) { } @Throws(Exception::class) - fun purchase(packageName: String, versionCode: Int, offerType: Int): List { - val buyResponse = getBuyResponse(packageName, versionCode, offerType) + fun purchase(packageName: String, versionCode: Int, offerType: Int, certificateHash: String = ""): List { + val deliveryToken = getDeliveryToken(packageName, versionCode, offerType, certificateHash) val deliveryResponse = getDeliveryResponse( packageName = packageName, updateVersionCode = versionCode, offerType = offerType, - downloadToken = buyResponse.encodedDeliveryToken + deliveryToken = deliveryToken, + certificateHash = certificateHash ) when (deliveryResponse.status) { 1 -> return getDownloadsFromDeliveryResponse(packageName, versionCode, deliveryResponse) + 2 -> throw ApiException.AppNotSupported() + 3 -> throw ApiException.AppNotPurchased() + + 7 -> + throw ApiException.AppRemoved() + + 9 -> + throw ApiException.AppNotSupported() + else -> throw ApiException.Unknown() } @@ -197,49 +258,61 @@ class PurchaseHelper(authData: AuthData) : BaseHelper(authData) { ): List { val fileList: MutableList = mutableListOf() if (deliveryResponse != null) { - //Add base apk + // Add base apk val androidAppDeliveryData = deliveryResponse.appDeliveryData if (androidAppDeliveryData != null) { - fileList.add(File().apply { - name = "${packageName}.apk" - url = androidAppDeliveryData.downloadUrl - size = androidAppDeliveryData.downloadSize - type = File.FileType.BASE - }) - - //Obb & patches (if any) + fileList.add( + File().apply { + name = "base.apk" + url = androidAppDeliveryData.downloadUrl + size = androidAppDeliveryData.downloadSize + type = File.FileType.BASE + sha1 = CertUtil.decodeHash(androidAppDeliveryData.sha1) + sha256 = CertUtil.decodeHash(androidAppDeliveryData.sha256) + } + ) + + // Obb & patches (if any) val fileMetadataList = deliveryResponse.appDeliveryData.additionalFileList if (fileMetadataList != null) { for (appFileMetadata in fileMetadataList) { val isOBB = appFileMetadata.fileType == 0 val fileType = if (isOBB) "main" else "patch" - fileList.add(File().apply { - name = "$fileType.$versionCode.$packageName.obb" - url = appFileMetadata.downloadUrl - size = appFileMetadata.size - type = if (isOBB) File.FileType.OBB else File.FileType.PATCH - }) + fileList.add( + File().apply { + name = "$fileType.$versionCode.$packageName.obb" + url = appFileMetadata.downloadUrl + size = appFileMetadata.size + type = if (isOBB) File.FileType.OBB else File.FileType.PATCH + sha1 = CertUtil.decodeHash(appFileMetadata.sha1) + } + ) } } - //Add split apks (if any) + // Add split apks (if any) val splitDeliveryDataList = deliveryResponse.appDeliveryData.splitDeliveryDataList if (fileMetadataList != null) { for (splitDeliveryData in splitDeliveryDataList) { - fileList.add(File().apply { - name = "${splitDeliveryData.name}.apk" - url = splitDeliveryData.downloadUrl - size = splitDeliveryData.downloadSize - type = File.FileType.SPLIT - }) + fileList.add( + File().apply { + name = "${splitDeliveryData.name}.apk" + url = splitDeliveryData.downloadUrl + size = splitDeliveryData.downloadSize + type = File.FileType.SPLIT + sha1 = CertUtil.decodeHash(splitDeliveryData.sha1) + sha256 = CertUtil.decodeHash(splitDeliveryData.sha256) + } + ) } } } } - if (fileList.isEmpty()) + if (fileList.isEmpty()) { throw ApiException.Unknown() + } return fileList } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/ReviewsHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/ReviewsHelper.kt similarity index 88% rename from src/main/java/com/aurora/gplayapi/helpers/ReviewsHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/ReviewsHelper.kt index e0439947a4215651d2369505f192b8ac64e93be7..7c2bb44d495f4e013ee2d32df20c6592b8a470b5 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/ReviewsHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/ReviewsHelper.kt @@ -23,7 +23,6 @@ import com.aurora.gplayapi.data.models.Review import com.aurora.gplayapi.data.models.ReviewCluster import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders import com.aurora.gplayapi.network.IHttpClient -import java.util.* class ReviewsHelper(authData: AuthData) : BaseHelper(authData) { @@ -44,10 +43,11 @@ class ReviewsHelper(authData: AuthData) : BaseHelper(authData) { ): ReviewResponse? { val responseBody = getResponse(url, params, headers) val payload = getPayLoadFromBytes(responseBody.responseBytes) - return if (payload.hasReviewResponse()) + return if (payload.hasReviewResponse()) { payload.reviewResponse - else + } else { null + } } @Throws(Exception::class) @@ -58,14 +58,18 @@ class ReviewsHelper(authData: AuthData) : BaseHelper(authData) { ): ReviewResponse? { val responseBody = getResponse(url, params, headers) val payload = getPayLoadFromBytes(responseBody.responseBytes) - return if (payload.hasReviewSummaryResponse()) + return if (payload.hasReviewSummaryResponse()) { payload.reviewSummaryResponse - else + } else { null + } } @Throws(Exception::class) - private fun postReviewResponse(params: Map, headers: Map): ReviewResponse? { + private fun postReviewResponse( + params: Map, + headers: Map + ): ReviewResponse? { val playResponse = httpClient.post(GooglePlayApi.URL_REVIEW_ADD_EDIT, headers, params) val payload = getPayLoadFromBytes(playResponse.responseBytes) return if (payload.hasReviewResponse()) payload.reviewResponse else null @@ -116,7 +120,8 @@ class ReviewsHelper(authData: AuthData) : BaseHelper(authData) { params["doc"] = packageName val headers: MutableMap = getDefaultHeaders(authData) - val reviewResponse = getReviewSummaryResponse("${GooglePlayApi.URL_FDFE}/reviewSummary", params, headers) + val reviewResponse = + getReviewSummaryResponse("${GooglePlayApi.URL_FDFE}/reviewSummary", params, headers) return getReviewCluster(reviewResponse).reviewList } @@ -139,7 +144,13 @@ class ReviewsHelper(authData: AuthData) : BaseHelper(authData) { } @Throws(Exception::class) - fun addOrEditReview(packageName: String, title: String, content: String, rating: Int, isBeta: Boolean): Review? { + fun addOrEditReview( + packageName: String, + title: String, + content: String, + rating: Int, + isBeta: Boolean + ): Review? { val params: MutableMap = HashMap() params["doc"] = packageName params["title"] = title @@ -162,7 +173,8 @@ class ReviewsHelper(authData: AuthData) : BaseHelper(authData) { fun next(nextPageUrl: String): ReviewCluster { val headers: MutableMap = getDefaultHeaders(authData) - val reviewResponse = getReviewResponse("${GooglePlayApi.URL_FDFE}/${nextPageUrl}", mapOf(), headers) + val reviewResponse = + getReviewResponse("${GooglePlayApi.URL_FDFE}/$nextPageUrl", mapOf(), headers) return getReviewCluster(reviewResponse) } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/SearchHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/SearchHelper.kt similarity index 89% rename from src/main/java/com/aurora/gplayapi/helpers/SearchHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/SearchHelper.kt index 2f94e07284ed5b77110ca31b70f3a6439a6a24cf..1c197d2c4bbda3cfbc9cb2901ebbc696c521f246 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/SearchHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/SearchHelper.kt @@ -27,9 +27,8 @@ import com.aurora.gplayapi.data.models.SearchBundle import com.aurora.gplayapi.data.models.SearchBundle.SubBundle import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders import com.aurora.gplayapi.network.IHttpClient -import java.util.* -class SearchHelper(authData: AuthData) : BaseHelper(authData) { +open class SearchHelper(authData: AuthData) : BaseHelper(authData) { private val searchTypeExtra = "_-" @@ -38,10 +37,12 @@ class SearchHelper(authData: AuthData) : BaseHelper(authData) { val nextPageUrl = item.containerMetadata.nextPageUrl if (nextPageUrl.isNotBlank()) { if (nextPageUrl.contains(searchTypeExtra)) { - if (nextPageUrl.startsWith("getCluster?enpt=CkC")) + if (nextPageUrl.startsWith("getCluster?enpt=CkC")) { return SubBundle(nextPageUrl, SearchBundle.Type.SIMILAR) - if (nextPageUrl.startsWith("getCluster?enpt=CkG")) + } + if (nextPageUrl.startsWith("getCluster?enpt=CkG")) { return SubBundle(nextPageUrl, SearchBundle.Type.RELATED_TO_YOUR_SEARCH) + } } else { return SubBundle(nextPageUrl, SearchBundle.Type.GENERIC) } @@ -58,7 +59,7 @@ class SearchHelper(authData: AuthData) : BaseHelper(authData) { private var query: String = String() @Throws(Exception::class) - fun searchSuggestions(query: String): List { + open fun searchSuggestions(query: String): List { val header: MutableMap = getDefaultHeaders(authData) val paramString = String.format( "?q=%s&sb=%d&sst=%d&sst=%d", @@ -71,11 +72,13 @@ class SearchHelper(authData: AuthData) : BaseHelper(authData) { val searchSuggestResponse = getSearchSuggestResponseFromBytes(responseBody.responseBytes) return if (searchSuggestResponse != null && searchSuggestResponse.entryCount > 0) { searchSuggestResponse.entryList - } else ArrayList() + } else { + ArrayList() + } } @Throws(Exception::class) - fun searchResults(query: String, nextPageUrl: String = ""): SearchBundle { + open fun searchResults(query: String, nextPageUrl: String = ""): SearchBundle { this.query = query val header: MutableMap = getDefaultHeaders(authData) val param: MutableMap = HashMap() @@ -106,7 +109,7 @@ class SearchHelper(authData: AuthData) : BaseHelper(authData) { } @Throws(Exception::class) - fun next(bundleSet: MutableSet): SearchBundle { + open fun next(bundleSet: MutableSet): SearchBundle { val compositeSearchBundle = SearchBundle() bundleSet.forEach { @@ -125,13 +128,14 @@ class SearchHelper(authData: AuthData) : BaseHelper(authData) { for (item in itemList) { if (item.subItemCount > 0) { for (subItem in item.subItemList) { - //Filter out only apps, discard other items (Music, Ebooks, Movies) + // Filter out only apps, discard other items (Music, Ebooks, Movies) if (subItem.type == 45) { if (subItem.title.isEmpty() || subItem.title == "Apps") { appList.addAll(getAppsFromItem(subItem)) } else { - if (subItem.title.isNotEmpty()) + if (subItem.title.isNotEmpty()) { continue // Filter out `You Might Also Like` & `Related Apps` + } appList.add(AppBuilder.build(subItem)) } } @@ -143,4 +147,4 @@ class SearchHelper(authData: AuthData) : BaseHelper(authData) { searchBundle.appList = appList return searchBundle } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/StreamHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/StreamHelper.kt similarity index 91% rename from src/main/java/com/aurora/gplayapi/helpers/StreamHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/StreamHelper.kt index febdfca513193ab3124e19338305128f5c904c37..04f7c0865705415d88e6df5e04656a94b2eeb998 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/StreamHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/StreamHelper.kt @@ -22,7 +22,6 @@ import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.editor.EditorChoiceBundle import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders import com.aurora.gplayapi.network.IHttpClient -import java.util.* class StreamHelper(authData: AuthData) : BaseHelper(authData) { @@ -56,16 +55,19 @@ class StreamHelper(authData: AuthData) : BaseHelper(authData) { if (type == Type.EARLY_ACCESS) { params["ct"] = "1" } else { - if (category != Category.NONE) + if (category != Category.NONE) { params["cat"] = category.value + } } - val playResponse = httpClient.get(GooglePlayApi.URL_FDFE + "/" + type.value, headers, params) + val playResponse = + httpClient.get(GooglePlayApi.URL_FDFE + "/" + type.value, headers, params) - return if (playResponse.isSuccessful) + return if (playResponse.isSuccessful) { getListResponseFromBytes(playResponse.responseBytes) - else + } else { ListResponse.getDefaultInstance() + } } enum class Category(var value: String) { @@ -83,4 +85,4 @@ class StreamHelper(authData: AuthData) : BaseHelper(authData) { SUB_NAV("subnavHome"), TOP_CHART("topChartsStream"); } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/TopChartsHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/TopChartsHelper.kt similarity index 98% rename from src/main/java/com/aurora/gplayapi/helpers/TopChartsHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/TopChartsHelper.kt index d6d30c9247defd9db8fe4f22fd74f2283216a975..d6d20069c8f5075f67ab9bf305afd462e429d461 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/TopChartsHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/TopChartsHelper.kt @@ -20,7 +20,6 @@ import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders import com.aurora.gplayapi.network.IHttpClient -import java.util.* class TopChartsHelper(authData: AuthData) : BaseHelper(authData) { @@ -40,12 +39,13 @@ class TopChartsHelper(authData: AuthData) : BaseHelper(authData) { return if (playResponse.isSuccessful) { val listResponse = getListResponseFromBytes(playResponse.responseBytes) getStreamCluster(listResponse) - } else + } else { StreamCluster() + } } enum class Type(var value: String) { GAME("GAME"), APPLICATION("APPLICATION"); } -} \ No newline at end of file +} diff --git a/src/main/java/com/aurora/gplayapi/helpers/UserProfileHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/UserProfileHelper.kt similarity index 99% rename from src/main/java/com/aurora/gplayapi/helpers/UserProfileHelper.kt rename to lib/src/main/java/com/aurora/gplayapi/helpers/UserProfileHelper.kt index 70e3493131f0549f83cf3c48bfbc5e9ffcff421f..c6bd9e837ad8e91e5b016e993e479ba698c020b5 100644 --- a/src/main/java/com/aurora/gplayapi/helpers/UserProfileHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/UserProfileHelper.kt @@ -50,4 +50,4 @@ class UserProfileHelper(authData: AuthData) : BaseHelper(authData) { null } } -} \ No newline at end of file +} diff --git a/lib/src/main/java/com/aurora/gplayapi/helpers/WebClient.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/WebClient.kt new file mode 100644 index 0000000000000000000000000000000000000000..87c5303f36cb0dfd2222b6b9f98e994492e4c043 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/WebClient.kt @@ -0,0 +1,60 @@ +/* + * GPlayApi + * Copyright (C) 2020 Aurora OSS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +package com.aurora.gplayapi.helpers + +import android.util.Log +import com.aurora.gplayapi.network.DefaultHttpClient.POST +import com.aurora.gplayapi.network.DefaultHttpClient.okHttpClient +import java.net.URLEncoder +import okhttp3.Headers.Companion.toHeaders +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody + +class WebClient { + + private val TAG = WebClient::class.java.simpleName + + fun fetch(rpcRequests: Array): String { + val url = "https://play.google.com/_/PlayStoreUi/data/batchexecute" + val headersList = mapOf( + "Content-Type" to "application/x-www-form-urlencoded;charset=utf-8", + "Origin" to "https://play.google.com" + ) + + val request = Request.Builder() + .url(url) + .headers(headersList.toHeaders()) + .method(POST, buildFRequest(rpcRequests).toRequestBody()) + .build() + + return try { + val response = okHttpClient.newCall(request).execute() + response.body!!.string() + } catch (exception: Exception) { + Log.e(TAG, "Failed to fetch request", exception) + String() + } + } + + private fun buildFRequest(rpcRequests: Array): String { + return """ + f.req=[[ + ${rpcRequests.joinToString(separator = ",") { URLEncoder.encode(it, "UTF-8") }} + ]] + """ + .trim() + } +} diff --git a/lib/src/main/java/com/aurora/gplayapi/helpers/WebSearchHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/WebSearchHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..85b5c408853309685f7a68933f76e3e973f3a077 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/WebSearchHelper.kt @@ -0,0 +1,104 @@ +package com.aurora.gplayapi.helpers + +import com.aurora.gplayapi.SearchSuggestEntry +import com.aurora.gplayapi.data.builders.rpc.RpcBuilder +import com.aurora.gplayapi.data.builders.rpc.SearchQueryBuilder +import com.aurora.gplayapi.data.builders.rpc.SearchSuggestionQueryBuilder +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.SearchBundle +import com.aurora.gplayapi.utils.dig + +class WebSearchHelper(authData: AuthData) : SearchHelper(authData) { + + private var query: String = String() + + @Throws(Exception::class) + override fun searchSuggestions(query: String): List { + val searchResponse = WebClient().fetch(arrayOf(SearchSuggestionQueryBuilder.build(query))) + .let { RpcBuilder.wrapResponse(it) } + + val payload = searchResponse.dig>( + SearchSuggestionQueryBuilder.TAG, + query, + 0 + ) + + if (payload.isNullOrEmpty()) { + return emptyList() + } + + val suggestions = payload.map { + SearchSuggestEntry.newBuilder().apply { + title = it.dig(0) + }.build() + } + + return suggestions + } + + @Throws(Exception::class) + override fun searchResults(query: String, nextPageUrl: String): SearchBundle { + this.query = query + + val searchBundle = SearchBundle() + val searchQuery = SearchQueryBuilder.build(query, nextPageUrl) + val searchResponse = WebClient().fetch(arrayOf(searchQuery)) + .let { RpcBuilder.wrapResponse(it) } + + var payload = searchResponse.dig>( + SearchQueryBuilder.TAG, + query, + 0 + ) + + if (payload.isNullOrEmpty()) { + return searchBundle + } + + // First stream is search stream, following are app streams (made-up names :p) + if (payload.dig(0, 1) != "Apps") { + payload = payload.dig(1, 0) + } + + // Find only the package names, complete app info is fetched via AppDetailsHelper + val packageNames: List = payload?.dig>(0, 0)?.let { entry -> + entry.mapNotNull { + it.dig(12, 0) + } + } ?: emptyList() + + if (packageNames.isEmpty()) { + return searchBundle + } + + val nextPageToken: String = payload?.dig(0, 7, 1) ?: "" + + searchBundle.apply { + this.appList = AppDetailsHelper(authData).getAppByPackageName(packageNames) + .toMutableList() + this.query = query + this.subBundles = hashSetOf() + } + + // Include sub-bundles only if there is a next page + if (nextPageToken.isNotEmpty()) { + val subBundle = SearchBundle.SubBundle(nextPageToken, SearchBundle.Type.GENERIC) + searchBundle.subBundles = hashSetOf(subBundle) + } + + return searchBundle + } + + @Throws(Exception::class) + override fun next(bundleSet: MutableSet): SearchBundle { + val compositeSearchBundle = SearchBundle() + + bundleSet.forEach { + val searchBundle = searchResults(query, it.nextPageUrl) + compositeSearchBundle.appList.addAll(searchBundle.appList) + compositeSearchBundle.subBundles.addAll(searchBundle.subBundles) + } + + return compositeSearchBundle + } +} diff --git a/lib/src/main/java/com/aurora/gplayapi/network/DefaultHttpClient.kt b/lib/src/main/java/com/aurora/gplayapi/network/DefaultHttpClient.kt new file mode 100644 index 0000000000000000000000000000000000000000..a20d4b70751196bb2010591c5d1c042f8d77f5b0 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/network/DefaultHttpClient.kt @@ -0,0 +1,165 @@ +/* + * GPlayApi + * Copyright (C) 2020 Aurora OSS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +package com.aurora.gplayapi.network + +import android.util.Log +import com.aurora.gplayapi.data.models.PlayResponse +import java.io.IOException +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import java.util.concurrent.TimeUnit +import okhttp3.Headers.Companion.toHeaders +import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response + +internal object DefaultHttpClient : IHttpClient { + + private const val TAG = "DefaultHttpClient" + + const val POST = "POST" + const val GET = "GET" + + private val _responseCode = MutableStateFlow(100) + override val responseCode: StateFlow + get() = _responseCode.asStateFlow() + + val okHttpClient = OkHttpClient().newBuilder() + .connectTimeout(25, TimeUnit.SECONDS) + .readTimeout(25, TimeUnit.SECONDS) + .writeTimeout(25, TimeUnit.SECONDS) + .retryOnConnectionFailure(true) + .followRedirects(true) + .followSslRedirects(true) + .build() + + override fun get(url: String, headers: Map): PlayResponse { + return get(url, headers, mapOf()) + } + + override fun get( + url: String, + headers: Map, + params: Map + ): PlayResponse { + val request = Request.Builder() + .url(buildUrl(url, params)) + .headers(headers.toHeaders()) + .method(GET, null) + .build() + return processRequest(request) + } + + override fun get( + url: String, + headers: Map, + paramString: String + ): PlayResponse { + val request = Request.Builder() + .url(url + paramString) + .headers(headers.toHeaders()) + .method(GET, null) + .build() + return processRequest(request) + } + + override fun getAuth(url: String): PlayResponse { + return PlayResponse().apply { + isSuccessful = false + code = 444 + } + } + + override fun postAuth(url: String, body: ByteArray): PlayResponse { + return PlayResponse().apply { + isSuccessful = false + code = 444 + } + } + + override fun post(url: String, headers: Map, body: ByteArray): PlayResponse { + val requestBody = body.toRequestBody( + "application/x-protobuf".toMediaType(), + 0, + body.size + ) + return post(url, headers, requestBody) + } + + override fun post( + url: String, + headers: Map, + params: Map + ): PlayResponse { + val request = Request.Builder() + .url(buildUrl(url, params)) + .headers(headers.toHeaders()) + .method(POST, "".toRequestBody(null)) + .build() + return processRequest(request) + } + + private fun processRequest(request: Request): PlayResponse { + // Reset response code as flow doesn't sends the same value twice + _responseCode.value = 0 + + val call = okHttpClient.newCall(request) + return buildPlayResponse(call.execute()) + } + + private fun buildUrl(url: String, params: Map): HttpUrl { + val urlBuilder = url.toHttpUrl().newBuilder() + params.forEach { + urlBuilder.addQueryParameter(it.key, it.value) + } + return urlBuilder.build() + } + + @Throws(IOException::class) + fun post(url: String, headers: Map, requestBody: RequestBody): PlayResponse { + val request = Request.Builder() + .url(url) + .headers(headers.toHeaders()) + .method(POST, requestBody) + .build() + return processRequest(request) + } + + @JvmStatic + private fun buildPlayResponse(response: Response): PlayResponse { + return PlayResponse().apply { + isSuccessful = response.isSuccessful + code = response.code + + if (response.body != null) { + responseBytes = response.body!!.bytes() + } + + if (!isSuccessful) { + errorString = response.message + } + }.also { + _responseCode.value = response.code + Log.d(TAG, "OKHTTP [${response.code}] ${response.request.url}") + } + } +} diff --git a/src/main/java/com/aurora/gplayapi/network/IHttpClient.kt b/lib/src/main/java/com/aurora/gplayapi/network/IHttpClient.kt similarity index 95% rename from src/main/java/com/aurora/gplayapi/network/IHttpClient.kt rename to lib/src/main/java/com/aurora/gplayapi/network/IHttpClient.kt index 2e9745c6eb4f6a3570381bfef9dbe34d7a8d64eb..3e3e3ba05519cbfc150702f13837b4e32ccad908 100644 --- a/src/main/java/com/aurora/gplayapi/network/IHttpClient.kt +++ b/lib/src/main/java/com/aurora/gplayapi/network/IHttpClient.kt @@ -16,9 +16,12 @@ package com.aurora.gplayapi.network import com.aurora.gplayapi.data.models.PlayResponse +import kotlinx.coroutines.flow.StateFlow import java.io.IOException interface IHttpClient { + val responseCode: StateFlow + @Throws(IOException::class) fun post(url: String, headers: Map, body: ByteArray): PlayResponse diff --git a/lib/src/main/java/com/aurora/gplayapi/utils/CertUtil.kt b/lib/src/main/java/com/aurora/gplayapi/utils/CertUtil.kt new file mode 100644 index 0000000000000000000000000000000000000000..1ea0e56a2dbee864903835e66e8be3c1b9430786 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/utils/CertUtil.kt @@ -0,0 +1,11 @@ +package com.aurora.gplayapi.utils + +import android.util.Base64 + +object CertUtil { + + @OptIn(ExperimentalStdlibApi::class) + fun decodeHash(base64EncodedHash: String): String { + return Base64.decode(base64EncodedHash, Base64.URL_SAFE).toHexString() + } +} diff --git a/lib/src/main/java/com/aurora/gplayapi/utils/Extensions.kt b/lib/src/main/java/com/aurora/gplayapi/utils/Extensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..13562cef7bf53d2757f28adef0751d79dcf15493 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/utils/Extensions.kt @@ -0,0 +1,26 @@ +package com.aurora.gplayapi.utils + +@Suppress("UNCHECKED_CAST") +fun Any.dig(vararg keys: Any): T? { + var current: Any? = this + keys.forEach { key -> + if (current == null) { + return null + } + current = when (current) { + is Collection<*> -> { + val index = key.toString().toIntOrNull() + index?.let { (current as Collection<*>).elementAtOrNull(it) } + } + + is Map<*, *> -> { + (current as Map<*, *>)[key] + } + + else -> { + null + } + } + } + return current as T +} diff --git a/src/main/java/com/aurora/gplayapi/utils/Util.java b/lib/src/main/java/com/aurora/gplayapi/utils/Util.java similarity index 100% rename from src/main/java/com/aurora/gplayapi/utils/Util.java rename to lib/src/main/java/com/aurora/gplayapi/utils/Util.java diff --git a/src/main/proto/GooglePlay.proto b/lib/src/main/proto/GooglePlay.proto similarity index 99% rename from src/main/proto/GooglePlay.proto rename to lib/src/main/proto/GooglePlay.proto index 54258e5de0a1efb8f05bbca6e8fc2187a69cb8ce..8845166ec29c7d09f4f072f5672814e3411e766b 100644 --- a/src/main/proto/GooglePlay.proto +++ b/lib/src/main/proto/GooglePlay.proto @@ -1019,6 +1019,16 @@ message AppDetails { optional string inAppProduct = 67; optional string downloadLabelAbbreviated = 77; optional string downloadLabel = 78; + optional Compatibility compatibility = 82; +} + +message Compatibility { + repeated ActiveDevice activeDevices = 1; +} + +message ActiveDevice { + optional string requiredOS = 1; + optional string name = 2; } message ModifyLibrary{ @@ -1045,8 +1055,8 @@ message EditorChoice{ } message CertificateSet { - repeated string certificateHash = 1; - repeated string sha256 = 2; + optional string certificateHash = 1; + optional string sha256 = 2; } message Dependencies { @@ -1056,6 +1066,7 @@ message Dependencies { optional int32 targetSdk = 4; optional int32 unknown2 = 5; repeated string splitApks = 11; + repeated LibraryDependency libraryDependency = 13; } message Dependency { @@ -1064,6 +1075,12 @@ message Dependency { optional int32 unknown4 = 4; } +message LibraryDependency { + optional string packageName = 1; + optional int32 versionCode = 2; +} + + message TestingProgramInfo { optional bool subscribed = 2; optional bool subscribedAndInstalled = 3; @@ -2167,4 +2184,4 @@ message ModifyLibraryRequest { optional string libraryId = 1; repeated string addPackageName = 2; repeated string removePackageName = 3; -} \ No newline at end of file +} diff --git a/src/main/resources/ad_g3_pro.properties b/lib/src/main/res/raw/gplayapi_ad_g3_pro.properties similarity index 100% rename from src/main/resources/ad_g3_pro.properties rename to lib/src/main/res/raw/gplayapi_ad_g3_pro.properties diff --git a/src/main/resources/bravia_atv2.properties b/lib/src/main/res/raw/gplayapi_bravia_atv2.properties similarity index 100% rename from src/main/resources/bravia_atv2.properties rename to lib/src/main/res/raw/gplayapi_bravia_atv2.properties diff --git a/lib/src/main/res/raw/gplayapi_bravia_vu2.properties b/lib/src/main/res/raw/gplayapi_bravia_vu2.properties new file mode 100644 index 0000000000000000000000000000000000000000..3e4fa200696683a1e84e6d77da0e499dd28f73e0 --- /dev/null +++ b/lib/src/main/res/raw/gplayapi_bravia_vu2.properties @@ -0,0 +1,50 @@ +# +# GPlayApi +# Copyright (C) 2023, The Calyx Institute +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +Build.BOOTLOADER=unknown +Build.BRAND=Sony +Build.DEVICE=BRAVIA_VU1_2K +Build.FINGERPRINT=Sony/BRAVIA_VU2/BRAVIA_VU1_2K\:11/RTT7.210923.001/146-60522\:user/release-keys +Build.HARDWARE=rtd2885m +Build.ID=RTT7.210923.001 +Build.MANUFACTURER=Sony +Build.MODEL=BRAVIA VU2 +Build.PRODUCT=BRAVIA_VU2 +Build.RADIO=unknown +Build.VERSION.RELEASE=11 +Build.VERSION.SDK_INT=30 +CellOperator=310 +Client=android-google +Features=android.software.leanback_only,android.software.adoptable_storage,android.hardware.hdmi.cec,android.software.backup,com.amazon.amazonvideo.livingroom.feature.AV_TARGET,android.hardware.ethernet,android.software.activities_on_secondary_displays,android.software.voice_recognizers,android.hardware.audio.low_latency,android.software.vulkan.deqp.level,android.software.cant_save_state,com.sony.dtv.software.braviachat,android.hardware.opengles.aep,android.hardware.type.television,android.hardware.bluetooth,android.software.incremental_delivery,android.hardware.usb.host,android.hardware.audio.output,android.software.verified_boot,android.hardware.gamepad,android.software.live_tv,nrdp.modelgroup,android.software.autofill,android.software.securely_removes_users,android.software.leanback,android.hardware.bluetooth_le,android.software.app_widgets,com.google.android.tv.installed,android.software.input_methods,com.sony.dtv.software.m2.devicecontrolservice,android.hardware.vulkan.version,android.hardware.wifi.passpoint,android.hardware.screen.landscape,com.google.android.feature.GLOBAL_ASSIST_TRIGGERING,android.hardware.ram.normal,android.software.webview,com.sony.dtv.software.braviaapp,android.hardware.camera.any,android.hardware.vulkan.compute,android.hardware.location.network,android.software.cts,android.software.app_enumeration,com.sony.dtv.software.m2.seeds_auth,android.hardware.wifi.direct,android.software.live_wallpaper,android.software.ipsec_tunnels,com.sony.devices,android.hardware.wifi,android.hardware.location,android.hardware.vulkan.level,android.hardware.camera.external,nrdp.validation,android.software.file_based_encryption +GL.Extensions=,GL_ANDROID_extension_pack_es31a,GL_ARM_mali_program_binary,GL_ARM_mali_shader_binary,GL_ARM_rgba8,GL_ARM_shader_framebuffer_fetch,GL_ARM_shader_framebuffer_fetch_depth_stencil,GL_ARM_texture_unnormalized_coordinates,GL_EXT_EGL_image_array,GL_EXT_YUV_target,GL_EXT_blend_minmax,GL_EXT_buffer_storage,GL_EXT_color_buffer_float,GL_EXT_color_buffer_half_float,GL_EXT_copy_image,GL_EXT_debug_marker,GL_EXT_discard_framebuffer,GL_EXT_disjoint_timer_query,GL_EXT_draw_buffers_indexed,GL_EXT_draw_elements_base_vertex,GL_EXT_external_buffer,GL_EXT_geometry_shader,GL_EXT_gpu_shader5,GL_EXT_multisampled_render_to_texture,GL_EXT_multisampled_render_to_texture2,GL_EXT_occlusion_query_boolean,GL_EXT_primitive_bounding_box,GL_EXT_protected_textures,GL_EXT_read_format_bgra,GL_EXT_robustness,GL_EXT_sRGB,GL_EXT_sRGB_write_control,GL_EXT_shader_io_blocks,GL_EXT_shader_non_constant_global_initializers,GL_EXT_shader_pixel_local_storage,GL_EXT_shadow_samplers,GL_EXT_tessellation_shader,GL_EXT_texture_border_clamp,GL_EXT_texture_buffer,GL_EXT_texture_compression_astc_decode_mode,GL_EXT_texture_compression_astc_decode_mode_rgb9e5,GL_EXT_texture_cube_map_array,GL_EXT_texture_format_BGRA8888,GL_EXT_texture_rg,GL_EXT_texture_sRGB_R8,GL_EXT_texture_sRGB_RG8,GL_EXT_texture_sRGB_decode,GL_EXT_texture_storage,GL_EXT_texture_type_2_10_10_10_REV,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_debug,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_OES_EGL_image,GL_OES_EGL_image_external,GL_OES_EGL_image_external_essl3,GL_OES_EGL_sync,GL_OES_blend_equation_separate,GL_OES_blend_func_separate,GL_OES_blend_subtract,GL_OES_byte_coordinates,GL_OES_compressed_ETC1_RGB8_texture,GL_OES_compressed_paletted_texture,GL_OES_copy_image,GL_OES_depth24,GL_OES_depth_texture,GL_OES_depth_texture_cube_map,GL_OES_draw_buffers_indexed,GL_OES_draw_elements_base_vertex,GL_OES_draw_texture,GL_OES_element_index_uint,GL_OES_extended_matrix_palette,GL_OES_fbo_render_mipmap,GL_OES_fixed_point,GL_OES_framebuffer_object,GL_OES_geometry_shader,GL_OES_get_program_binary,GL_OES_gpu_shader5,GL_OES_mapbuffer,GL_OES_matrix_get,GL_OES_matrix_palette,GL_OES_packed_depth_stencil,GL_OES_point_size_array,GL_OES_point_sprite,GL_OES_primitive_bounding_box,GL_OES_query_matrix,GL_OES_read_format,GL_OES_required_internalformat,GL_OES_rgb8_rgba8,GL_OES_sample_shading,GL_OES_sample_variables,GL_OES_shader_image_atomic,GL_OES_shader_io_blocks,GL_OES_shader_multisample_interpolation,GL_OES_single_precision,GL_OES_standard_derivatives,GL_OES_stencil8,GL_OES_stencil_wrap,GL_OES_surfaceless_context,GL_OES_tessellation_shader,GL_OES_texture_3D,GL_OES_texture_border_clamp,GL_OES_texture_buffer,GL_OES_texture_compression_astc,GL_OES_texture_cube_map,GL_OES_texture_cube_map_array,GL_OES_texture_mirrored_repeat,GL_OES_texture_npot,GL_OES_texture_stencil8,GL_OES_texture_storage_multisample_2d_array,GL_OES_vertex_array_object,GL_OES_vertex_half_float,GL_OVR_multiview,GL_OVR_multiview2,GL_OVR_multiview_multisampled_render_to_texture +GL.Version=196610 +GSF.version=203615037 +HasFiveWayNavigation=true +HasHardKeyboard=false +Keyboard=1 +Locales=af,af_ZA,am,ar,ar_EG,as,ast,az,be,bg,bn,bn_IN,bs,ca,ckb,cs,da,de,el,en,en_AU,en_CA,en_GB,en_IN,en_US,en_XC,eo,es,es_419,es_US,et,eu,fa,fa_IR,fi,fil,fr,fr_CA,fr_FR,gl,gu,gu_IN,he,hi,hi_IN,hr,ht,hu,hy,ia,id,in,in_ID,is,it,iw,ja,ka,kab,kk,km,kmr,kn,kn_IN,ko,ky,lo,lt,lv,mk,ml,ml_IN,mn,mr,mr_IN,ms,my,nb,nb_NO,ne,nl,or,pa,pa_IN,pl,pt,pt_BR,pt_PT,ro,ru,ru_RU,sc,si,sk,sl,so,sq,sr,sr_Latn,sv,sw,sw_TZ,ta,ta_IN,te,te_IN,th,th_TH,tr,uk,ur,uz,vi,vi_VN,yue,zh_CN,zh_HK,zh_TW,zu,zu_ZA +Navigation=2 +Platforms=armeabi-v7a,armeabi +Roaming=mobile-notroaming +Screen.Density=213 +Screen.Height=720 +Screen.Width=1280 +ScreenLayout=3 +SharedLibraries=android.test.base,android.test.mock,rtk-mediaplayer,android.hidl.manager-V1.0-java,android.hidl.base-V1.0-java,customer-framework,com.android.location.provider,android.net.ipsec.ike,com.android.future.usb.accessory,rtk-framework,android.ext.shared,javax.obex,com.google.android.gms,android.test.runner,org.apache.http.legacy,com.android.media.remotedisplay,com.android.media.tv.remoteprovider,com.android.mediadrm.signer +SimOperator=38 +TimeZone=UTC-10 +TouchScreen=1 +UserReadableName=BRAVIA VU2 +Vending.version=82201710 +Vending.versionString=22.0.17-21 [0] [PR] 332555730 diff --git a/src/main/resources/fp_2.properties b/lib/src/main/res/raw/gplayapi_fp_2.properties similarity index 100% rename from src/main/resources/fp_2.properties rename to lib/src/main/res/raw/gplayapi_fp_2.properties diff --git a/src/main/resources/hw_h9.properties b/lib/src/main/res/raw/gplayapi_hw_h9.properties similarity index 100% rename from src/main/resources/hw_h9.properties rename to lib/src/main/res/raw/gplayapi_hw_h9.properties diff --git a/src/main/resources/hw_mate20.properties b/lib/src/main/res/raw/gplayapi_hw_mate20.properties similarity index 100% rename from src/main/resources/hw_mate20.properties rename to lib/src/main/res/raw/gplayapi_hw_mate20.properties diff --git a/src/main/resources/mi_8_se.properties b/lib/src/main/res/raw/gplayapi_mi_8_se.properties similarity index 100% rename from src/main/resources/mi_8_se.properties rename to lib/src/main/res/raw/gplayapi_mi_8_se.properties diff --git a/src/main/resources/mi_a1.properties b/lib/src/main/res/raw/gplayapi_mi_a1.properties similarity index 100% rename from src/main/resources/mi_a1.properties rename to lib/src/main/res/raw/gplayapi_mi_a1.properties diff --git a/src/main/resources/mi_mix2.properties b/lib/src/main/res/raw/gplayapi_mi_mix2.properties similarity index 100% rename from src/main/resources/mi_mix2.properties rename to lib/src/main/res/raw/gplayapi_mi_mix2.properties diff --git a/src/main/resources/moto_g5.properties b/lib/src/main/res/raw/gplayapi_moto_g5.properties similarity index 100% rename from src/main/resources/moto_g5.properties rename to lib/src/main/res/raw/gplayapi_moto_g5.properties diff --git a/src/main/resources/nk_8.properties b/lib/src/main/res/raw/gplayapi_nk_8.properties similarity index 100% rename from src/main/resources/nk_8.properties rename to lib/src/main/res/raw/gplayapi_nk_8.properties diff --git a/src/main/resources/nk_9.properties b/lib/src/main/res/raw/gplayapi_nk_9.properties similarity index 100% rename from src/main/resources/nk_9.properties rename to lib/src/main/res/raw/gplayapi_nk_9.properties diff --git a/src/main/resources/nk_drx.properties b/lib/src/main/res/raw/gplayapi_nk_drx.properties similarity index 100% rename from src/main/resources/nk_drx.properties rename to lib/src/main/res/raw/gplayapi_nk_drx.properties diff --git a/src/main/resources/op_3.properties b/lib/src/main/res/raw/gplayapi_op_3.properties similarity index 100% rename from src/main/resources/op_3.properties rename to lib/src/main/res/raw/gplayapi_op_3.properties diff --git a/src/main/resources/op_5.properties b/lib/src/main/res/raw/gplayapi_op_5.properties similarity index 100% rename from src/main/resources/op_5.properties rename to lib/src/main/res/raw/gplayapi_op_5.properties diff --git a/src/main/resources/op_5t.properties b/lib/src/main/res/raw/gplayapi_op_5t.properties similarity index 100% rename from src/main/resources/op_5t.properties rename to lib/src/main/res/raw/gplayapi_op_5t.properties diff --git a/src/main/resources/op_6.properties b/lib/src/main/res/raw/gplayapi_op_6.properties similarity index 100% rename from src/main/resources/op_6.properties rename to lib/src/main/res/raw/gplayapi_op_6.properties diff --git a/src/main/resources/op_7t.properties b/lib/src/main/res/raw/gplayapi_op_7t.properties similarity index 100% rename from src/main/resources/op_7t.properties rename to lib/src/main/res/raw/gplayapi_op_7t.properties diff --git a/src/main/resources/op_7t_pro.properties b/lib/src/main/res/raw/gplayapi_op_7t_pro.properties similarity index 100% rename from src/main/resources/op_7t_pro.properties rename to lib/src/main/res/raw/gplayapi_op_7t_pro.properties diff --git a/src/main/resources/op_8_pro.properties b/lib/src/main/res/raw/gplayapi_op_8_pro.properties similarity index 100% rename from src/main/resources/op_8_pro.properties rename to lib/src/main/res/raw/gplayapi_op_8_pro.properties diff --git a/src/main/resources/op_x.properties b/lib/src/main/res/raw/gplayapi_op_x.properties similarity index 100% rename from src/main/resources/op_x.properties rename to lib/src/main/res/raw/gplayapi_op_x.properties diff --git a/src/main/resources/poco_f1.properties b/lib/src/main/res/raw/gplayapi_poco_f1.properties similarity index 100% rename from src/main/resources/poco_f1.properties rename to lib/src/main/res/raw/gplayapi_poco_f1.properties diff --git a/src/main/resources/px_3a.properties b/lib/src/main/res/raw/gplayapi_px_3a.properties similarity index 100% rename from src/main/resources/px_3a.properties rename to lib/src/main/res/raw/gplayapi_px_3a.properties diff --git a/lib/src/main/res/raw/gplayapi_px_7a.properties b/lib/src/main/res/raw/gplayapi_px_7a.properties new file mode 100644 index 0000000000000000000000000000000000000000..cd31be5c78e8ca1af81e4d8f4839273c66217a6d --- /dev/null +++ b/lib/src/main/res/raw/gplayapi_px_7a.properties @@ -0,0 +1,50 @@ +# +# GPlayApi +# Copyright (C) 2023, The Calyx Institute +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +Build.BOOTLOADER=lynx-1.0-9716681 +Build.BRAND=google +Build.DEVICE=lynx +Build.FINGERPRINT=google/lynx/lynx\:13/TQ2B.230505.005.A1/9808202\:user/release-keys +Build.HARDWARE=lynx +Build.ID=TQ2A.230505.002 +Build.MANUFACTURER=Google +Build.MODEL=Pixel 7a +Build.PRODUCT=lynx +Build.RADIO=g5300n-230203-230323-B-9801058,g5300n-230203-230323-B-9801058 +Build.VERSION.RELEASE=13 +Build.VERSION.SDK_INT=33 +CellOperator=310 +Client=android-google +Features=android.hardware.sensor.proximity,android.hardware.telephony.ims.singlereg,android.hardware.sensor.accelerometer,android.software.controls,android.hardware.faketouch,android.software.telecom,android.hardware.telephony.subscription,android.hardware.telephony.euicc,android.hardware.usb.accessory,android.hardware.telephony.data,android.hardware.sensor.dynamic.head_tracker,android.software.backup,android.hardware.touchscreen,android.hardware.touchscreen.multitouch,android.software.erofs,android.software.print,android.software.activities_on_secondary_displays,android.hardware.wifi.rtt,com.google.android.feature.PIXEL_2017_EXPERIENCE,android.software.voice_recognizers,android.software.picture_in_picture,android.hardware.fingerprint,android.hardware.sensor.gyroscope,android.hardware.audio.low_latency,android.software.vulkan.deqp.level,android.software.cant_save_state,com.google.android.feature.PIXEL_2018_EXPERIENCE,android.hardware.security.model.compatible,android.hardware.telephony.messaging,com.google.android.feature.PIXEL_2019_EXPERIENCE,android.hardware.telephony.calling,android.hardware.opengles.aep,org.lineageos.livedisplay,android.hardware.bluetooth,android.software.window_magnification,android.hardware.telephony.radio.access,android.hardware.camera.autofocus,android.hardware.telephony.gsm,android.hardware.telephony.ims,android.software.incremental_delivery,android.hardware.se.omapi.ese,android.software.opengles.deqp.level,vendor.android.hardware.camera.preview-dis.front,com.google.android.feature.PIXEL_2022_MIDYEAR_EXPERIENCE,android.hardware.camera.concurrent,android.hardware.usb.host,android.hardware.audio.output,android.software.verified_boot,android.hardware.camera.flash,android.hardware.camera.front,android.hardware.sensor.hifi_sensors,android.hardware.se.omapi.uicc,android.hardware.strongbox_keystore,android.hardware.screen.portrait,android.hardware.nfc,com.nxp.mifare,com.google.android.feature.PIXEL_2021_MIDYEAR_EXPERIENCE,android.hardware.sensor.stepdetector,android.software.home_screen,android.hardware.context_hub,vendor.android.hardware.camera.preview-dis.back,android.hardware.microphone,android.software.autofill,org.lineageos.hardware,org.lineageos.globalactions,android.software.securely_removes_users,com.google.android.feature.PIXEL_EXPERIENCE,android.hardware.bluetooth_le,android.hardware.sensor.compass,android.hardware.touchscreen.multitouch.jazzhand,android.hardware.sensor.barometer,android.software.app_widgets,com.google.android.feature.PIXEL_2020_MIDYEAR_EXPERIENCE,android.hardware.telephony.carrierlock,android.software.input_methods,android.hardware.sensor.light,android.hardware.vulkan.version,android.software.companion_device_setup,android.software.device_admin,android.hardware.wifi.passpoint,android.hardware.camera,org.lineageos.trust,android.hardware.device_unique_attestation,android.hardware.screen.landscape,android.software.device_id_attestation,android.hardware.ram.normal,com.google.android.feature.PIXEL_2019_MIDYEAR_EXPERIENCE,android.software.managed_users,android.software.webview,android.hardware.sensor.stepcounter,android.hardware.camera.capability.manual_post_processing,android.hardware.camera.any,android.hardware.camera.capability.raw,android.hardware.vulkan.compute,android.hardware.touchscreen.multitouch.distinct,android.hardware.location.network,android.software.cts,android.hardware.camera.capability.manual_sensor,android.software.app_enumeration,android.hardware.camera.level.full,android.hardware.identity_credential,android.hardware.wifi.direct,android.software.live_wallpaper,com.google.android.feature.GOOGLE_EXPERIENCE,android.software.ipsec_tunnels,org.lineageos.settings,android.hardware.audio.pro,android.hardware.nfc.hcef,android.hardware.location.gps,android.software.midi,android.hardware.nfc.any,android.hardware.nfc.ese,android.hardware.nfc.hce,android.hardware.hardware_keystore,com.google.android.feature.PIXEL_2020_EXPERIENCE,android.hardware.telephony.euicc.mep,android.hardware.wifi,android.hardware.location,android.hardware.vulkan.level,com.google.android.feature.PIXEL_2021_EXPERIENCE,android.hardware.keystore.app_attest_key,android.hardware.wifi.aware,com.google.android.feature.PIXEL_2022_EXPERIENCE,android.software.secure_lock_screen,android.hardware.telephony,android.software.file_based_encryption +GL.Extensions=,GL_ANDROID_extension_pack_es31a,GL_ARM_mali_program_binary,GL_ARM_mali_shader_binary,GL_ARM_rgba8,GL_ARM_shader_framebuffer_fetch,GL_ARM_shader_framebuffer_fetch_depth_stencil,GL_ARM_texture_unnormalized_coordinates,GL_EXT_EGL_image_array,GL_EXT_YUV_target,GL_EXT_blend_minmax,GL_EXT_buffer_storage,GL_EXT_clip_control,GL_EXT_color_buffer_float,GL_EXT_color_buffer_half_float,GL_EXT_copy_image,GL_EXT_debug_marker,GL_EXT_discard_framebuffer,GL_EXT_disjoint_timer_query,GL_EXT_draw_buffers_indexed,GL_EXT_draw_elements_base_vertex,GL_EXT_external_buffer,GL_EXT_float_blend,GL_EXT_geometry_shader,GL_EXT_gpu_shader5,GL_EXT_multisampled_render_to_texture,GL_EXT_multisampled_render_to_texture2,GL_EXT_occlusion_query_boolean,GL_EXT_primitive_bounding_box,GL_EXT_protected_textures,GL_EXT_read_format_bgra,GL_EXT_robustness,GL_EXT_sRGB,GL_EXT_sRGB_write_control,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_io_blocks,GL_EXT_shader_non_constant_global_initializers,GL_EXT_shader_pixel_local_storage,GL_EXT_shadow_samplers,GL_EXT_tessellation_shader,GL_EXT_texture_border_clamp,GL_EXT_texture_buffer,GL_EXT_texture_compression_astc_decode_mode,GL_EXT_texture_compression_astc_decode_mode_rgb9e5,GL_EXT_texture_cube_map_array,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_format_BGRA8888,GL_EXT_texture_rg,GL_EXT_texture_sRGB_R8,GL_EXT_texture_sRGB_RG8,GL_EXT_texture_sRGB_decode,GL_EXT_texture_storage,GL_EXT_texture_type_2_10_10_10_REV,GL_EXT_unpack_subimage,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_debug,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_OES_EGL_image,GL_OES_EGL_image_external,GL_OES_EGL_image_external_essl3,GL_OES_EGL_sync,GL_OES_blend_equation_separate,GL_OES_blend_func_separate,GL_OES_blend_subtract,GL_OES_byte_coordinates,GL_OES_compressed_ETC1_RGB8_texture,GL_OES_compressed_paletted_texture,GL_OES_copy_image,GL_OES_depth24,GL_OES_depth_texture,GL_OES_depth_texture_cube_map,GL_OES_draw_buffers_indexed,GL_OES_draw_elements_base_vertex,GL_OES_draw_texture,GL_OES_element_index_uint,GL_OES_extended_matrix_palette,GL_OES_fbo_render_mipmap,GL_OES_fixed_point,GL_OES_framebuffer_object,GL_OES_geometry_shader,GL_OES_get_program_binary,GL_OES_gpu_shader5,GL_OES_mapbuffer,GL_OES_matrix_get,GL_OES_matrix_palette,GL_OES_packed_depth_stencil,GL_OES_point_size_array,GL_OES_point_sprite,GL_OES_primitive_bounding_box,GL_OES_query_matrix,GL_OES_read_format,GL_OES_required_internalformat,GL_OES_rgb8_rgba8,GL_OES_sample_shading,GL_OES_sample_variables,GL_OES_shader_image_atomic,GL_OES_shader_io_blocks,GL_OES_shader_multisample_interpolation,GL_OES_single_precision,GL_OES_standard_derivatives,GL_OES_stencil8,GL_OES_stencil_wrap,GL_OES_surfaceless_context,GL_OES_tessellation_shader,GL_OES_texture_3D,GL_OES_texture_border_clamp,GL_OES_texture_buffer,GL_OES_texture_compression_astc,GL_OES_texture_cube_map,GL_OES_texture_cube_map_array,GL_OES_texture_float_linear,GL_OES_texture_mirrored_repeat,GL_OES_texture_npot,GL_OES_texture_stencil8,GL_OES_texture_storage_multisample_2d_array,GL_OES_vertex_array_object,GL_OES_vertex_half_float,GL_OVR_multiview,GL_OVR_multiview2,GL_OVR_multiview_multisampled_render_to_texture +GL.Version=196610 +GSF.version=203615037 +HasFiveWayNavigation=false +HasHardKeyboard=false +Keyboard=1 +Locales=af,af_ZA,am,am_ET,ar,ar_EG,ar_XB,as,ast,ast_ES,az,be,bg,bg_BG,bn,bs,ca,ca_ES,ckb,cs,cs_CZ,cy,da,da_DK,de,de_DE,el,el_GR,en,en_AU,en_CA,en_GB,en_IN,en_US,en_XA,en_XC,eo,es,es_419,es_ES,es_US,et,eu,fa,fa_IR,fi,fi_FI,fil,fil_PH,fr,fr_CA,fr_FR,gd,gl,gu,he,hi,hi_IN,hr,hr_HR,ht,hu,hu_HU,hy,ia,id,in,in_ID,is,it,it_IT,iw,iw_IL,ja,ja_JP,ka,kab,kk,km,kmr,kn,ko,ko_KR,ky,lo,lt,lt_LT,lv,lv_LV,mk,ml,mn,mr,ms,ms_MY,my,nb,nb_NO,ne,nl,nl_NL,or,pa,pl,pl_PL,pt,pt_BR,pt_PT,ro,ro_RO,ru,ru_RU,sc,si,sk,sk_SK,sl,sl_SI,so,sq,sr,sr_Latn,sr_RS,sv,sv_SE,sw,sw_TZ,ta,te,th,th_TH,tr,tr_TR,uk,uk_UA,ur,uz,vi,vi_VN,zh_CN,zh_HK,zh_TW,zu,zu_ZA +Navigation=1 +Platforms=arm64-v8a +Roaming=mobile-notroaming +Screen.Density=420 +Screen.Height=2156 +Screen.Width=1080 +ScreenLayout=2 +SharedLibraries=android.test.base,android.test.mock,android.hidl.manager-V1.0-java,google-ril,libedgetpu_client.google.so,libedgetpu_util.so,android.hidl.base-V1.0-java,com.google.android.camera.experimental2022,libOpenCL-pixel.so,com.android.location.provider,oemrilhook,android.net.ipsec.ike,com.android.future.usb.accessory,android.ext.shared,javax.obex,com.google.android.gms,lib_aion_buffer.so,libgxp.so,gxp_metrics_logger.so,android.test.runner,org.apache.http.legacy,com.android.cts.ctsshim.shared_library,com.android.nfc_extras,com.android.media.remotedisplay,com.android.mediadrm.signer,android.system.virtualmachine +SimOperator=38 +TimeZone=UTC-10 +TouchScreen=3 +UserReadableName=Google Pixel 7a +Vending.version=82201710 +Vending.versionString=22.0.17-21 [0] [PR] 332555730 diff --git a/lib/src/main/res/raw/gplayapi_px_tablet.properties b/lib/src/main/res/raw/gplayapi_px_tablet.properties new file mode 100644 index 0000000000000000000000000000000000000000..7a93449a11003e1b980872e704763de021648af2 --- /dev/null +++ b/lib/src/main/res/raw/gplayapi_px_tablet.properties @@ -0,0 +1,50 @@ +# +# GPlayApi +# Copyright (C) 2023, The Calyx Institute +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +Build.BOOTLOADER=tangorpro-1.0-9883529 +Build.BRAND=google +Build.DEVICE=tangorpro +Build.FINGERPRINT=google/tangorpro/tangorpro\:13/TQ3A.230605.009.A1/10100517\:user/release-keys +Build.HARDWARE=tangorpro +Build.ID=TQ3A.230605.012 +Build.MANUFACTURER=Google +Build.MODEL=Pixel Tablet +Build.PRODUCT=tangorpro +Build.RADIO=unknown +Build.VERSION.RELEASE=13 +Build.VERSION.SDK_INT=33 +CellOperator=310 +Client=android-google +Features=android.hardware.sensor.accelerometer,android.software.controls,android.hardware.faketouch,android.software.telecom,android.hardware.usb.accessory,android.hardware.sensor.dynamic.head_tracker,android.software.backup,android.hardware.touchscreen,android.hardware.touchscreen.multitouch,android.software.erofs,android.software.print,android.software.activities_on_secondary_displays,android.hardware.wifi.rtt,com.google.android.feature.PIXEL_2017_EXPERIENCE,android.software.voice_recognizers,android.software.picture_in_picture,android.hardware.fingerprint,android.hardware.sensor.gyroscope,android.hardware.audio.low_latency,android.software.vulkan.deqp.level,android.software.cant_save_state,com.google.android.feature.PIXEL_2018_EXPERIENCE,android.hardware.security.model.compatible,com.google.android.feature.PIXEL_2019_EXPERIENCE,android.hardware.opengles.aep,org.lineageos.livedisplay,android.hardware.bluetooth,android.software.window_magnification,android.software.incremental_delivery,android.software.opengles.deqp.level,vendor.android.hardware.camera.preview-dis.front,com.google.android.feature.PIXEL_2022_MIDYEAR_EXPERIENCE,android.hardware.camera.concurrent,android.hardware.usb.host,android.hardware.audio.output,android.software.verified_boot,android.hardware.camera.front,android.hardware.strongbox_keystore,android.hardware.screen.portrait,android.hardware.uwb,com.google.android.feature.PIXEL_2021_MIDYEAR_EXPERIENCE,android.hardware.sensor.stepdetector,android.software.home_screen,android.hardware.context_hub,vendor.android.hardware.camera.preview-dis.back,android.hardware.microphone,com.google.android.feature.PIXEL_TABLET_2023_EXPERIENCE,android.software.autofill,org.lineageos.hardware,org.lineageos.globalactions,android.software.securely_removes_users,com.google.android.feature.PIXEL_EXPERIENCE,android.hardware.bluetooth_le,android.hardware.sensor.compass,android.hardware.touchscreen.multitouch.jazzhand,android.software.app_widgets,com.google.android.feature.PIXEL_2020_MIDYEAR_EXPERIENCE,android.software.input_methods,android.hardware.sensor.light,android.hardware.vulkan.version,android.software.companion_device_setup,android.software.device_admin,android.hardware.wifi.passpoint,android.hardware.camera,org.lineageos.trust,android.hardware.device_unique_attestation,android.hardware.screen.landscape,android.software.device_id_attestation,android.hardware.ram.normal,vendor.android.hardware.camera.stream-usecase,com.google.android.feature.PIXEL_2019_MIDYEAR_EXPERIENCE,android.software.managed_users,android.software.webview,android.hardware.sensor.stepcounter,android.hardware.camera.capability.manual_post_processing,android.hardware.camera.any,android.hardware.camera.capability.raw,android.hardware.vulkan.compute,android.hardware.touchscreen.multitouch.distinct,android.hardware.location.network,android.software.cts,android.hardware.camera.capability.manual_sensor,android.software.app_enumeration,android.hardware.camera.level.full,android.hardware.identity_credential,android.hardware.wifi.direct,android.software.live_wallpaper,com.google.android.feature.GOOGLE_EXPERIENCE,android.software.ipsec_tunnels,org.lineageos.settings,android.hardware.audio.pro,android.software.midi,android.hardware.hardware_keystore,com.google.android.feature.PIXEL_2020_EXPERIENCE,android.hardware.wifi,android.hardware.location,android.hardware.vulkan.level,com.google.android.feature.PIXEL_2021_EXPERIENCE,android.hardware.keystore.app_attest_key,android.hardware.wifi.aware,com.google.android.feature.PIXEL_2022_EXPERIENCE,android.software.secure_lock_screen,android.software.file_based_encryption +GL.Extensions=,GL_ANDROID_extension_pack_es31a,GL_ARM_mali_program_binary,GL_ARM_mali_shader_binary,GL_ARM_rgba8,GL_ARM_shader_framebuffer_fetch,GL_ARM_shader_framebuffer_fetch_depth_stencil,GL_ARM_texture_unnormalized_coordinates,GL_EXT_EGL_image_array,GL_EXT_YUV_target,GL_EXT_blend_minmax,GL_EXT_buffer_storage,GL_EXT_clip_control,GL_EXT_color_buffer_float,GL_EXT_color_buffer_half_float,GL_EXT_copy_image,GL_EXT_debug_marker,GL_EXT_discard_framebuffer,GL_EXT_disjoint_timer_query,GL_EXT_draw_buffers_indexed,GL_EXT_draw_elements_base_vertex,GL_EXT_external_buffer,GL_EXT_float_blend,GL_EXT_geometry_shader,GL_EXT_gpu_shader5,GL_EXT_multisampled_render_to_texture,GL_EXT_multisampled_render_to_texture2,GL_EXT_occlusion_query_boolean,GL_EXT_primitive_bounding_box,GL_EXT_protected_textures,GL_EXT_read_format_bgra,GL_EXT_robustness,GL_EXT_sRGB,GL_EXT_sRGB_write_control,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_io_blocks,GL_EXT_shader_non_constant_global_initializers,GL_EXT_shader_pixel_local_storage,GL_EXT_shadow_samplers,GL_EXT_tessellation_shader,GL_EXT_texture_border_clamp,GL_EXT_texture_buffer,GL_EXT_texture_compression_astc_decode_mode,GL_EXT_texture_compression_astc_decode_mode_rgb9e5,GL_EXT_texture_cube_map_array,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_format_BGRA8888,GL_EXT_texture_rg,GL_EXT_texture_sRGB_R8,GL_EXT_texture_sRGB_RG8,GL_EXT_texture_sRGB_decode,GL_EXT_texture_storage,GL_EXT_texture_type_2_10_10_10_REV,GL_EXT_unpack_subimage,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_debug,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_OES_EGL_image,GL_OES_EGL_image_external,GL_OES_EGL_image_external_essl3,GL_OES_EGL_sync,GL_OES_blend_equation_separate,GL_OES_blend_func_separate,GL_OES_blend_subtract,GL_OES_byte_coordinates,GL_OES_compressed_ETC1_RGB8_texture,GL_OES_compressed_paletted_texture,GL_OES_copy_image,GL_OES_depth24,GL_OES_depth_texture,GL_OES_depth_texture_cube_map,GL_OES_draw_buffers_indexed,GL_OES_draw_elements_base_vertex,GL_OES_draw_texture,GL_OES_element_index_uint,GL_OES_extended_matrix_palette,GL_OES_fbo_render_mipmap,GL_OES_fixed_point,GL_OES_framebuffer_object,GL_OES_geometry_shader,GL_OES_get_program_binary,GL_OES_gpu_shader5,GL_OES_mapbuffer,GL_OES_matrix_get,GL_OES_matrix_palette,GL_OES_packed_depth_stencil,GL_OES_point_size_array,GL_OES_point_sprite,GL_OES_primitive_bounding_box,GL_OES_query_matrix,GL_OES_read_format,GL_OES_required_internalformat,GL_OES_rgb8_rgba8,GL_OES_sample_shading,GL_OES_sample_variables,GL_OES_shader_image_atomic,GL_OES_shader_io_blocks,GL_OES_shader_multisample_interpolation,GL_OES_single_precision,GL_OES_standard_derivatives,GL_OES_stencil8,GL_OES_stencil_wrap,GL_OES_surfaceless_context,GL_OES_tessellation_shader,GL_OES_texture_3D,GL_OES_texture_border_clamp,GL_OES_texture_buffer,GL_OES_texture_compression_astc,GL_OES_texture_cube_map,GL_OES_texture_cube_map_array,GL_OES_texture_float_linear,GL_OES_texture_mirrored_repeat,GL_OES_texture_npot,GL_OES_texture_stencil8,GL_OES_texture_storage_multisample_2d_array,GL_OES_vertex_array_object,GL_OES_vertex_half_float,GL_OVR_multiview,GL_OVR_multiview2,GL_OVR_multiview_multisampled_render_to_texture +GL.Version=196610 +GSF.version=203615037 +HasFiveWayNavigation=false +HasHardKeyboard=false +Keyboard=1 +Locales=af,af_ZA,am,am_ET,ar,ar_EG,ar_XB,as,ast,ast_ES,az,be,bg,bg_BG,bn,bs,ca,ca_ES,ckb,cs,cs_CZ,cy,da,da_DK,de,de_DE,el,el_GR,en,en_AU,en_CA,en_GB,en_IN,en_US,en_XA,en_XC,eo,es,es_419,es_ES,es_US,et,eu,fa,fa_IR,fi,fi_FI,fil,fil_PH,fr,fr_CA,fr_FR,gd,gl,gu,he,hi,hi_IN,hr,hr_HR,ht,hu,hu_HU,hy,ia,id,in,in_ID,is,it,it_IT,iw,iw_IL,ja,ja_JP,ka,kab,kk,km,kmr,kn,ko,ko_KR,ky,lo,lt,lt_LT,lv,lv_LV,mk,ml,mn,mr,ms,ms_MY,my,nb,nb_NO,ne,nl,nl_NL,or,pa,pl,pl_PL,pt,pt_BR,pt_PT,ro,ro_RO,ru,ru_RU,sc,si,sk,sk_SK,sl,sl_SI,so,sq,sr,sr_Latn,sr_RS,sv,sv_SE,sw,sw_TZ,ta,te,th,th_TH,tr,tr_TR,uk,uk_UA,ur,uz,vi,vi_VN,yue,zh_CN,zh_HK,zh_TW,zu,zu_ZA +Navigation=1 +Platforms=arm64-v8a +Roaming=mobile-notroaming +Screen.Density=320 +Screen.Height=2496 +Screen.Width=1600 +ScreenLayout=4 +SharedLibraries=android.test.base,android.test.mock,android.hidl.manager-V1.0-java,libedgetpu_client.google.so,libedgetpu_util.so,android.hidl.base-V1.0-java,com.google.android.camera.experimental2022,libOpenCL-pixel.so,com.android.location.provider,android.net.ipsec.ike,com.android.future.usb.accessory,android.ext.shared,libaudio_proxy.google.so,javax.obex,com.google.android.gms,lib_aion_buffer.so,libgxp.so,gxp_metrics_logger.so,android.test.runner,org.apache.http.legacy,com.android.cts.ctsshim.shared_library,com.android.nfc_extras,com.android.media.remotedisplay,com.android.mediadrm.signer,android.system.virtualmachine +SimOperator=38 +TimeZone=UTC-10 +TouchScreen=3 +UserReadableName=Google Pixel Tablet +Vending.version=82201710 +Vending.versionString=22.0.17-21 [0] [PR] 332555730 diff --git a/src/main/resources/rm_4.properties b/lib/src/main/res/raw/gplayapi_rm_4.properties similarity index 100% rename from src/main/resources/rm_4.properties rename to lib/src/main/res/raw/gplayapi_rm_4.properties diff --git a/src/main/resources/rm_5.properties b/lib/src/main/res/raw/gplayapi_rm_5.properties similarity index 100% rename from src/main/resources/rm_5.properties rename to lib/src/main/res/raw/gplayapi_rm_5.properties diff --git a/src/main/resources/rm_5_plus.properties b/lib/src/main/res/raw/gplayapi_rm_5_plus.properties similarity index 100% rename from src/main/resources/rm_5_plus.properties rename to lib/src/main/res/raw/gplayapi_rm_5_plus.properties diff --git a/src/main/resources/rm_5_pro.properties b/lib/src/main/res/raw/gplayapi_rm_5_pro.properties similarity index 100% rename from src/main/resources/rm_5_pro.properties rename to lib/src/main/res/raw/gplayapi_rm_5_pro.properties diff --git a/src/main/resources/rm_5i.properties b/lib/src/main/res/raw/gplayapi_rm_5i.properties similarity index 100% rename from src/main/resources/rm_5i.properties rename to lib/src/main/res/raw/gplayapi_rm_5i.properties diff --git a/src/main/resources/rm_7.properties b/lib/src/main/res/raw/gplayapi_rm_7.properties similarity index 100% rename from src/main/resources/rm_7.properties rename to lib/src/main/res/raw/gplayapi_rm_7.properties diff --git a/src/main/resources/rm_k20_pro.properties b/lib/src/main/res/raw/gplayapi_rm_k20_pro.properties similarity index 100% rename from src/main/resources/rm_k20_pro.properties rename to lib/src/main/res/raw/gplayapi_rm_k20_pro.properties diff --git a/src/main/resources/rm_note_3.properties b/lib/src/main/res/raw/gplayapi_rm_note_3.properties similarity index 100% rename from src/main/resources/rm_note_3.properties rename to lib/src/main/res/raw/gplayapi_rm_note_3.properties diff --git a/src/main/resources/rm_note_5.properties b/lib/src/main/res/raw/gplayapi_rm_note_5.properties similarity index 100% rename from src/main/resources/rm_note_5.properties rename to lib/src/main/res/raw/gplayapi_rm_note_5.properties diff --git a/src/main/resources/sm_a3.properties b/lib/src/main/res/raw/gplayapi_sm_a3.properties similarity index 100% rename from src/main/resources/sm_a3.properties rename to lib/src/main/res/raw/gplayapi_sm_a3.properties diff --git a/src/main/resources/sm_feel.properties b/lib/src/main/res/raw/gplayapi_sm_feel.properties similarity index 100% rename from src/main/resources/sm_feel.properties rename to lib/src/main/res/raw/gplayapi_sm_feel.properties diff --git a/src/main/resources/sm_s7.properties b/lib/src/main/res/raw/gplayapi_sm_s7.properties similarity index 100% rename from src/main/resources/sm_s7.properties rename to lib/src/main/res/raw/gplayapi_sm_s7.properties diff --git a/src/main/resources/sm_s8.properties b/lib/src/main/res/raw/gplayapi_sm_s8.properties similarity index 100% rename from src/main/resources/sm_s8.properties rename to lib/src/main/res/raw/gplayapi_sm_s8.properties diff --git a/src/main/resources/sm_s9_plus.properties b/lib/src/main/res/raw/gplayapi_sm_s9_plus.properties similarity index 100% rename from src/main/resources/sm_s9_plus.properties rename to lib/src/main/res/raw/gplayapi_sm_s9_plus.properties diff --git a/src/main/resources/tw_e.properties b/lib/src/main/res/raw/gplayapi_tw_e.properties similarity index 100% rename from src/main/resources/tw_e.properties rename to lib/src/main/res/raw/gplayapi_tw_e.properties diff --git a/lib/src/main/res/raw/gplayapi_xm_11a.properties b/lib/src/main/res/raw/gplayapi_xm_11a.properties new file mode 100644 index 0000000000000000000000000000000000000000..c85ca2aa1d21d92dca1239535d6a48ab8916ba5f --- /dev/null +++ b/lib/src/main/res/raw/gplayapi_xm_11a.properties @@ -0,0 +1,50 @@ +# +# GPlayApi +# Copyright (C) 2023, The Calyx Institute +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +Build.BOOTLOADER=unknown +Build.BRAND=Xiaomi +Build.DEVICE=lisa +Build.FINGERPRINT=Xiaomi/lisa_eea/lisa\:13/TKQ1.220829.002/V14.0.6.0.TKOEUXM\:user/release-keys +Build.HARDWARE=qcom +Build.ID=TKQ1.220829.002 +Build.MANUFACTURER=Xiaomi +Build.MODEL=2109119DG +Build.PRODUCT=lisa_eea +Build.RADIO=4.3CPL2-gl-26.1-15406.340227_2053_1f271b2afea,4.3CPL2-gl-26.1-15406.340227_2053_1f271b2afea +Build.VERSION.RELEASE=13 +Build.VERSION.SDK_INT=33 +CellOperator=310 +Client=android-google +Features=android.hardware.sensor.proximity,com.google.android.feature.ASI_MINIMAL,com.quicinc.voice.assist.uvr,android.software.adoptable_storage,android.hardware.sensor.accelerometer,android.software.controls,android.hardware.faketouch,com.google.android.feature.D2D_CABLE_MIGRATION_FEATURE,android.hardware.usb.accessory,android.hardware.telephony.cdma,android.software.backup,android.hardware.touchscreen,android.hardware.touchscreen.multitouch,android.software.print,android.hardware.consumerir,android.software.activities_on_secondary_displays,android.software.voice_recognizers,com.google.lens.feature.CAMERA_INTEGRATION,android.software.picture_in_picture,android.hardware.fingerprint,android.hardware.sensor.gyroscope,android.hardware.audio.low_latency,com.google.android.feature.PERSONAL_SAFETY,android.software.vulkan.deqp.level,android.software.cant_save_state,android.hardware.security.model.compatible,android.hardware.opengles.aep,android.hardware.bluetooth,android.hardware.camera.autofocus,android.hardware.telephony.gsm,android.hardware.telephony.ims,android.software.incremental_delivery,android.software.sip.voip,android.hardware.se.omapi.ese,android.hardware.usb.host,android.hardware.audio.output,android.software.verified_boot,android.hardware.camera.flash,android.hardware.camera.front,android.hardware.se.omapi.uicc,android.hardware.screen.portrait,android.hardware.nfc,com.google.android.feature.TURBO_PRELOAD,com.nxp.mifare,android.hardware.sensor.stepdetector,android.software.home_screen,android.hardware.microphone,android.software.autofill,android.software.securely_removes_users,android.hardware.bluetooth_le,android.hardware.sensor.compass,android.hardware.touchscreen.multitouch.jazzhand,android.software.app_widgets,android.software.input_methods,android.hardware.sensor.light,android.hardware.vulkan.version,android.software.companion_device_setup,com.google.android.feature.EEA_V2_DEVICE,android.software.device_admin,com.google.android.feature.WELLBEING,android.hardware.wifi.passpoint,android.hardware.camera,android.hardware.screen.landscape,com.google.android.feature.AER_OPTIMIZED,android.hardware.ram.normal,android.software.managed_users,android.software.webview,android.hardware.sensor.stepcounter,android.hardware.camera.capability.manual_post_processing,com.google.lens.feature.IMAGE_INTEGRATION,android.hardware.camera.any,android.hardware.camera.capability.raw,android.hardware.vulkan.compute,com.google.android.apps.dialer.call_recording_audio,android.software.connectionservice,android.hardware.touchscreen.multitouch.distinct,android.hardware.location.network,android.software.cts,android.software.sip,android.hardware.camera.capability.manual_sensor,android.software.app_enumeration,com.google.android.apps.dialer.SUPPORTED,android.hardware.camera.level.full,com.google.android.feature.EEA_DEVICE,android.hardware.wifi.direct,android.software.live_wallpaper,android.software.ipsec_tunnels,com.google.android.paid.chrome,com.quicinc.voice.assist,android.hardware.nfc.hcef,android.hardware.nfc.uicc,android.hardware.location.gps,android.software.midi,android.hardware.nfc.any,android.hardware.nfc.ese,android.hardware.nfc.hce,android.hardware.wifi,android.hardware.location,com.google.android.paid.search,android.hardware.vulkan.level,com.google.android.feature.PREMIER_TIER,android.software.secure_lock_screen,android.hardware.telephony,android.software.file_based_encryption +GL.Extensions=,GL_AMD_compressed_ATC_texture,GL_AMD_performance_monitor,GL_ANDROID_extension_pack_es31a,GL_APPLE_texture_2D_limited_npot,GL_ARB_vertex_buffer_object,GL_ARM_shader_framebuffer_fetch_depth_stencil,GL_EXT_EGL_image_array,GL_EXT_EGL_image_external_wrap_modes,GL_EXT_EGL_image_storage,GL_EXT_YUV_target,GL_EXT_blend_func_extended,GL_EXT_blit_framebuffer_params,GL_EXT_buffer_storage,GL_EXT_clip_control,GL_EXT_clip_cull_distance,GL_EXT_color_buffer_float,GL_EXT_color_buffer_half_float,GL_EXT_copy_image,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_discard_framebuffer,GL_EXT_disjoint_timer_query,GL_EXT_draw_buffers_indexed,GL_EXT_external_buffer,GL_EXT_fragment_invocation_density,GL_EXT_geometry_shader,GL_EXT_gpu_shader5,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_multisampled_render_to_texture,GL_EXT_multisampled_render_to_texture2,GL_EXT_primitive_bounding_box,GL_EXT_protected_textures,GL_EXT_read_format_bgra,GL_EXT_robustness,GL_EXT_sRGB,GL_EXT_sRGB_write_control,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_io_blocks,GL_EXT_shader_non_constant_global_initializers,GL_EXT_tessellation_shader,GL_EXT_texture_border_clamp,GL_EXT_texture_buffer,GL_EXT_texture_cube_map_array,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_format_BGRA8888,GL_EXT_texture_format_sRGB_override,GL_EXT_texture_norm16,GL_EXT_texture_sRGB_R8,GL_EXT_texture_sRGB_decode,GL_EXT_texture_type_2_10_10_10_REV,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_debug,GL_KHR_no_error,GL_KHR_robust_buffer_access_behavior,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_NV_shader_noperspective_interpolation,GL_OES_EGL_image,GL_OES_EGL_image_external,GL_OES_EGL_image_external_essl3,GL_OES_EGL_sync,GL_OES_blend_equation_separate,GL_OES_blend_func_separate,GL_OES_blend_subtract,GL_OES_compressed_ETC1_RGB8_texture,GL_OES_compressed_paletted_texture,GL_OES_depth24,GL_OES_depth_texture,GL_OES_depth_texture_cube_map,GL_OES_draw_texture,GL_OES_element_index_uint,GL_OES_framebuffer_object,GL_OES_get_program_binary,GL_OES_matrix_palette,GL_OES_packed_depth_stencil,GL_OES_point_size_array,GL_OES_point_sprite,GL_OES_read_format,GL_OES_rgb8_rgba8,GL_OES_sample_shading,GL_OES_sample_variables,GL_OES_shader_image_atomic,GL_OES_shader_multisample_interpolation,GL_OES_standard_derivatives,GL_OES_stencil_wrap,GL_OES_surfaceless_context,GL_OES_texture_3D,GL_OES_texture_compression_astc,GL_OES_texture_cube_map,GL_OES_texture_env_crossbar,GL_OES_texture_float,GL_OES_texture_float_linear,GL_OES_texture_half_float,GL_OES_texture_half_float_linear,GL_OES_texture_mirrored_repeat,GL_OES_texture_npot,GL_OES_texture_stencil8,GL_OES_texture_storage_multisample_2d_array,GL_OES_texture_view,GL_OES_vertex_array_object,GL_OES_vertex_half_float,GL_OVR_multiview,GL_OVR_multiview2,GL_OVR_multiview_multisampled_render_to_texture,GL_QCOM_YUV_texture_gather,GL_QCOM_alpha_test,GL_QCOM_extended_get,GL_QCOM_motion_estimation,GL_QCOM_shader_framebuffer_fetch_noncoherent,GL_QCOM_shader_framebuffer_fetch_rate,GL_QCOM_shading_rate,GL_QCOM_texture_foveated,GL_QCOM_texture_foveated_subsampled_layout,GL_QCOM_tiled_rendering,GL_QCOM_validate_shader_binary +GL.Version=196610 +GSF.version=203615037 +HasFiveWayNavigation=false +HasHardKeyboard=false +Keyboard=1 +Locales=af,am,ar,ar_EG,ar_XB,as,as_IN,ast,az,az_AZ,be,be_BY,bg,bg_BG,bn,bn_BD,bn_IN,bs,bs_BA,ca,ca_ES,ckb,cs,cs_CZ,da,da_DK,de,de_DE,el,el_GR,en,en_AU,en_CA,en_GB,en_IN,en_US,en_XA,en_XC,eo,es,es_419,es_ES,es_US,et,et_EE,eu,eu_ES,fa,fa_IR,fi,fi_FI,fil,fr,fr_CA,fr_FR,gl,gl_ES,gu,gu_IN,ha_NG,he,hi,hi_IN,hr,hr_HR,ht,hu,hu_HU,hy,hy_AM,ia,id,in,in_ID,is,it,it_IT,iw,iw_IL,ja,ja_JP,ka,ka_GE,kab,kk,kk_KZ,km,km_KH,kmr,kn,kn_IN,ko,ko_KR,ky,lo,lo_LA,lt,lt_LT,lv,lv_LV,mk,mk_MK,ml,ml_IN,mn,mr,mr_IN,ms,ms_MY,mt_MT,my,my_MM,nb,nb_NO,ne,ne_IN,ne_NP,nl,nl_NL,or,or_IN,pa,pa_IN,pl,pl_PL,pt,pt_BR,pt_PT,ro,ro_RO,ru,ru_RU,sc,si,sk,sk_SK,sl,sl_SI,so,sq,sq_AL,sr,sr_Latn,sr_RS,sv,sv_SE,sw,ta,ta_IN,te,te_IN,th,th_TH,tr,tr_TR,uk,uk_UA,ur,ur_IN,ur_PK,uz,uz_UZ,vi,vi_VN,zh,zh_CN,zh_HK,zh_TW,zu +Navigation=1 +Platforms=arm64-v8a,armeabi-v7a,armeabi +Roaming=mobile-notroaming +Screen.Density=440 +Screen.Height=2296 +Screen.Width=1080 +ScreenLayout=2 +SharedLibraries=libhoaeffects.qti.so,android.test.base,android.test.mock,libqti-perfd-client.so,android.hidl.manager-V1.0-java,libupdateprof.qti.so,qti-telephony-hidl-wrapper,libfastcvopt.so,vendor.qti.ims.connection-V1.0-java,liblistenjni.qti.so,android.hidl.manager.V1_0.IServiceNotification,com.android.hotwordenrollment.common.util,android.hidl.manager.V1_0.IServiceManager,libOpenCL.so,libthermalclient.qti.so,vendor.xiaomi.hardware.misys-V1.0-java,vendor.qti.ims.rcsuce-V1.0-java,com.qualcomm.qti.uimGba.uimgbalibrary,vendor.qti.ims.rcsuce-V1.1-java,vendor.qti.ims.rcsuce-V1.2-java,dpmapi,qti-telephony-utils,com.qti.location.sdk,libbinauralrenderer_wrapper.qti.so,services.core,camerax-vendor-extensions.jar,libdiag_system.qti.so,com.qualcomm.qti.uimGbaManager.uimgbamanagerlibrary,com.qti.media.secureprocessor,qti-telephony-utils-prd,global-cleaner-empty.jar,ims-ext-common,libcdsprpc.so,android.hidl.base-V1.0-java,com.qualcomm.qmapbridge,libmisys_jni.xiaomi.so,com.qualcomm.qti.remoteSimlock.manager.remotesimlockmanagerlibrary,com.qualcomm.qti.audiosphere,libadsprpc.so,com.android.location.provider,vendor.xiaomi.hardware.misys-V4.0-java,com.miui.system,android.hidl.base.V1_0.IBase,com.wapi.wapicertstore,vendor.xiaomi.hardware.misys.V3_0,android.hardware.wifi.supplicant.V1_3.ISupplicant,android.net.ipsec.ike,security-device-credential-sdk.jar,com.nxp.nfc.nq,com.android.future.usb.accessory,version-seperation-dev,android.hardware.wifi.supplicant.V1_2.ISupplicant,com.qti.dpmframework,libsdsprpc.so,android.ext.shared,vendor.xiaomi.hardware.misys-V2.0-java,javax.obex,izat.xt.srv,android.hardware.wifi.supplicant.V1_1.ISupplicant,com.google.android.gms,MiuiSettingsSearchLib.jar,libsnpe_dsp_domains_v2.so,libsnpe_dsp_domains_v3.so,com.qualcomm.qti.uim.uimservicelibrary,libhta.so,com.fingerprints.extension,com.qualcomm.uimremoteclientlibrary,android.hardware.wifi.supplicant.V1_0.ISupplicant,liblistensoundmodel2.so,com.xiaomi.nfc,vendor.qti.ims.factory-V2.0-java,vendor.qti.ims.factory-V2.1-java,com.xiaomi.slalib,vendor.qti.ims.factory-V2.2-java,com.xiaomi.NetworkBoost,com.qti.extphone.extphonelib,vendor.xiaomi.hardware.bgservice-V1.0-java,com.qualcomm.qti.remoteSimlock.uimremotesimlocklibrary,com.qualcomm.uimremoteserverlibrary,libQOC.qti.so,com.qualcomm.qcrilhook,android.test.runner,gson.jar,libSNPE.so,com.google.android.dialer.support,org.apache.http.legacy,vendor.qti.ims.rcssip-V1.0-java,vendor.qti.ims.rcssip-V1.1-java,com.android.cts.ctsshim.shared_library,com.android.nfc_extras,com.android.media.remotedisplay,com.qti.extphone.extphonelib-product,vendor.qti.ims.rcssip-V1.2-java,com.android.mediadrm.signer,com.qualcomm.qti.imscmservice-V2.0-java,qti-telephony-hidl-wrapper-prd,com.qti.snapdragon.sdk.display,com.qualcomm.qti.imscmservice-V2.1-java,com.qualcomm.qti.imscmservice-V2.2-java,libqape.qti.so,com.miui.core,micloud-sdk,com.qualcomm.embmslibrary +SimOperator=38 +TimeZone=UTC-10 +TouchScreen=3 +UserReadableName=Xiaomi 11 Lite 5G NE +Vending.version=82201710 +Vending.versionString=22.0.17-21 [0] [PR] 332555730 diff --git a/src/main/resources/xp_5_dual.properties b/lib/src/main/res/raw/gplayapi_xp_5_dual.properties similarity index 100% rename from src/main/resources/xp_5_dual.properties rename to lib/src/main/res/raw/gplayapi_xp_5_dual.properties diff --git a/lib/src/main/res/raw/keep.xml b/lib/src/main/res/raw/keep.xml new file mode 100644 index 0000000000000000000000000000000000000000..f0030e899dc9d738001234bc68870bf593caf770 --- /dev/null +++ b/lib/src/main/res/raw/keep.xml @@ -0,0 +1,3 @@ + + diff --git a/sampleapp/.gitignore b/sampleapp/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..42afabfd2abebf31384ca7797186a27a4b7dbee8 --- /dev/null +++ b/sampleapp/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/sampleapp/build.gradle.kts b/sampleapp/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..ae6fa2f492eb6843dce35f69aa3c39e7defad723 --- /dev/null +++ b/sampleapp/build.gradle.kts @@ -0,0 +1,79 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "com.aurora.sampleapp" + compileSdk = 34 + + defaultConfig { + applicationId = "com.aurora.sampleapp" + minSdk = 33 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + buildConfigField("String", "GPLAY_API_EMAIL", "\"${System.getenv("GPLAY_API_EMAIL")}\"") + buildConfigField("String", "GPLAY_API_TOKEN", "\"${System.getenv("GPLAY_API_TOKEN")}\"") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } + buildFeatures { + buildConfig = true + compose = true + } + composeOptions { + kotlinCompilerExtensionVersion = "1.5.8" + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } +} + +dependencies { + + // API + implementation(project(":lib")) + + implementation("androidx.core:core-ktx:1.12.0") + implementation("androidx.activity:activity-compose:1.8.2") + implementation(platform("androidx.compose:compose-bom:2023.10.01")) + implementation("androidx.compose.ui:ui") + implementation("androidx.compose.ui:ui-graphics") + implementation("androidx.compose.ui:ui-tooling-preview") + implementation("androidx.compose.material3:material3") + + // Coil + implementation("io.coil-kt:coil-compose:2.5.0") + + // LifeCycle + val lifecycleVersion = "2.7.0" + implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion") + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleVersion") + implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycleVersion") + + // Protobuf + implementation("com.google.protobuf:protobuf-javalite:3.25.2") +} diff --git a/sampleapp/proguard-rules.pro b/sampleapp/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..481bb434814107eb79d7a30b676d344b0df2f8ce --- /dev/null +++ b/sampleapp/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# 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 + +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/sampleapp/src/main/AndroidManifest.xml b/sampleapp/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..893b961b1c96c9ba7f952881e950011c2ebdfb20 --- /dev/null +++ b/sampleapp/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + diff --git a/sampleapp/src/main/java/com/aurora/sampleapp/MainActivity.kt b/sampleapp/src/main/java/com/aurora/sampleapp/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..b01146c3f7b5c88967111adfac90715413b2ef7e --- /dev/null +++ b/sampleapp/src/main/java/com/aurora/sampleapp/MainActivity.kt @@ -0,0 +1,77 @@ +package com.aurora.sampleapp + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.viewModels +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import coil.compose.AsyncImage +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.sampleapp.ui.theme.GPlayApiTheme + +class MainActivity : ComponentActivity() { + + private val viewModel: MainActivityViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + GPlayApiTheme { + Scaffold() { + val context = LocalContext.current + LaunchedEffect(key1 = Unit) { viewModel.buildAuthData(context) } + + Column( + modifier = Modifier + .padding(it) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + + val authData: AuthData by viewModel.authData.collectAsStateWithLifecycle() + + if (authData.email.isNotBlank()) { + AsyncImage( + modifier = Modifier + .padding(10.dp) + .requiredSize(192.dp) + .clip(RoundedCornerShape(20.dp)), + model = authData.userProfile?.artwork?.url, + contentDescription = "" + ) + + Text( + modifier = Modifier.padding(vertical = 20.dp), + text = authData.email + ) + + Button(onClick = { viewModel.doSomething(context) }) { + Text(text = "Do something!") + } + } else { + CircularProgressIndicator(modifier = Modifier.requiredSize(100.dp)) + } + } + } + } + } + } +} diff --git a/sampleapp/src/main/java/com/aurora/sampleapp/MainActivityViewModel.kt b/sampleapp/src/main/java/com/aurora/sampleapp/MainActivityViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..a47788bf534f2679187df2f93637ec1c9c627e43 --- /dev/null +++ b/sampleapp/src/main/java/com/aurora/sampleapp/MainActivityViewModel.kt @@ -0,0 +1,38 @@ +package com.aurora.sampleapp + +import android.content.Context +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.aurora.gplayapi.DeviceManager +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.helpers.AuthHelper +import java.util.Properties +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch + +class MainActivityViewModel : ViewModel() { + + private val _authData = MutableStateFlow(AuthData("", "")) + val authData = _authData.asStateFlow() + + fun buildAuthData(context: Context) { + viewModelScope.launch(Dispatchers.IO) { + val properties = Properties() + context.resources.openRawResource(com.aurora.gplayapi.R.raw.gplayapi_px_7a).use { + properties.load(it) + } + + _authData.value = AuthHelper.build( + BuildConfig.GPLAY_API_EMAIL, + BuildConfig.GPLAY_API_TOKEN, + properties + ) + } + } + + fun doSomething(context: Context) { + // Run the thing you want to test here! + } +} diff --git a/sampleapp/src/main/java/com/aurora/sampleapp/ui/theme/Theme.kt b/sampleapp/src/main/java/com/aurora/sampleapp/ui/theme/Theme.kt new file mode 100644 index 0000000000000000000000000000000000000000..6acb6b7e8c22d06eaaea95034a0cf935594fa8ff --- /dev/null +++ b/sampleapp/src/main/java/com/aurora/sampleapp/ui/theme/Theme.kt @@ -0,0 +1,43 @@ +package com.aurora.sampleapp.ui.theme + +import android.app.Activity +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Typography +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +@Composable +fun GPlayApiTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { + val context = LocalContext.current + val colorScheme = if (darkTheme) { + dynamicDarkColorScheme(context) + } else { + dynamicLightColorScheme(context) + } + + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.background.toArgb() + window.navigationBarColor = colorScheme.background.toArgb() + WindowCompat.getInsetsController(window, view).apply { + isAppearanceLightStatusBars = !darkTheme + isAppearanceLightNavigationBars = !darkTheme + } + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography(), + content = content + ) +} diff --git a/sampleapp/src/main/res/drawable/ic_launcher_foreground.xml b/sampleapp/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000000000000000000000000000000000000..9cc493debb2979caf2fd1cac71d507c36b8ba0b1 --- /dev/null +++ b/sampleapp/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/sampleapp/src/main/res/mipmap-anydpi/ic_launcher.xml b/sampleapp/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000000000000000000000000000000000000..7353dbd1fd82487df2d06121f85f7994728f1070 --- /dev/null +++ b/sampleapp/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/sampleapp/src/main/res/values/colors.xml b/sampleapp/src/main/res/values/colors.xml new file mode 100644 index 0000000000000000000000000000000000000000..ad6f6d9631c090a33e334308f20aff6734395a3c --- /dev/null +++ b/sampleapp/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #3DDC84 + diff --git a/sampleapp/src/main/res/values/strings.xml b/sampleapp/src/main/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..d40f731451397b89b8539c8089e379cd65161748 --- /dev/null +++ b/sampleapp/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Sample App + \ No newline at end of file diff --git a/sampleapp/src/main/res/values/themes.xml b/sampleapp/src/main/res/values/themes.xml new file mode 100644 index 0000000000000000000000000000000000000000..55f4d44b987e8fb93872bde05787db05023bdfd4 --- /dev/null +++ b/sampleapp/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +