mirror of
https://github.com/whyorean/AuroraStore.git
synced 2026-05-18 21:35:43 -04:00
Initial v4
This commit is contained in:
43
.gitignore
vendored
Normal file
43
.gitignore
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Built application files
|
||||
*.apk
|
||||
*.ap_
|
||||
|
||||
# Files for the Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
|
||||
# Gitlab files
|
||||
.gitlab/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
/*/build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
# From .gitignore generated by Android Studio
|
||||
*.iml
|
||||
.DS_Store
|
||||
/captures
|
||||
/.idea
|
||||
/.gradle*
|
||||
gradle-app.setting
|
||||
*.zip
|
||||
|
||||
app/release/*
|
||||
app/beta/*
|
||||
app/alpha/*
|
||||
1
app/.gitignore
vendored
Normal file
1
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
166
app/build.gradle
Normal file
166
app/build.gradle
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: "androidx.navigation.safeargs.kotlin"
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.aurora.store"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 30
|
||||
|
||||
versionCode 30
|
||||
versionName "4.0.1"
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
zipAlignEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
||||
beta {
|
||||
initWith release
|
||||
applicationIdSuffix = ".beta"
|
||||
}
|
||||
|
||||
debug {
|
||||
applicationIdSuffix = ".debug"
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
versions = [
|
||||
okhttp3 : "4.9.0",
|
||||
fetch2 : "3.1.6",
|
||||
fuel : "2.3.0",
|
||||
glide : "4.11.0",
|
||||
lifecycle: "2.3.0",
|
||||
epoxy : "4.3.1",
|
||||
libsu : "2.5.1"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
|
||||
//MultiDex for Kitkat support
|
||||
implementation("androidx.multidex:multidex:2.0.1")
|
||||
|
||||
//Protobuf
|
||||
implementation("com.google.protobuf:protobuf-java:3.14.0")
|
||||
|
||||
//Apache's Goodies
|
||||
implementation("commons-io:commons-io:2.7")
|
||||
implementation("org.apache.commons:commons-text:1.8")
|
||||
|
||||
//Google's Goodies
|
||||
implementation("com.google.android.material:material:1.3.0")
|
||||
implementation("com.google.android:flexbox:2.0.1")
|
||||
implementation("com.google.code.gson:gson:2.8.6")
|
||||
|
||||
//AndroidX
|
||||
implementation("androidx.core:core-ktx:1.3.2")
|
||||
implementation("androidx.viewpager2:viewpager2:1.0.0")
|
||||
implementation("androidx.vectordrawable:vectordrawable:1.1.0")
|
||||
implementation("androidx.preference:preference-ktx:1.1.1")
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||
|
||||
//Arch LifeCycle
|
||||
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:${versions.lifecycle}")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:${versions.lifecycle}")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:${versions.lifecycle}")
|
||||
|
||||
//Arch Navigation
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:${navigation}")
|
||||
implementation("androidx.navigation:navigation-runtime-ktx:${navigation}")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:${navigation}")
|
||||
|
||||
//UI Addons
|
||||
implementation("com.github.florent37:expansionpanel:1.2.4")
|
||||
|
||||
//Easy Permission
|
||||
implementation("com.github.quickpermissions:quickpermissions-kotlin:0.4.0")
|
||||
|
||||
//Glide
|
||||
implementation("com.github.bumptech.glide:glide:${versions.glide}")
|
||||
kapt("com.github.bumptech.glide:compiler:${versions.glide}")
|
||||
|
||||
//Shimmer
|
||||
implementation("com.facebook.shimmer:shimmer:0.5.0")
|
||||
|
||||
//Epoxy
|
||||
implementation("com.airbnb.android:epoxy:${versions.epoxy}")
|
||||
kapt("com.airbnb.android:epoxy-processor:${versions.epoxy}")
|
||||
|
||||
//Merlin
|
||||
implementation("com.novoda:merlin:1.2.0")
|
||||
|
||||
//HTTP Clients
|
||||
implementation("com.github.kittinunf.fuel:fuel:${versions.fuel}")
|
||||
implementation("com.squareup.okhttp3:okhttp:${versions.okhttp3}")
|
||||
|
||||
//Fetch - Downloader
|
||||
implementation "androidx.tonyodev.fetch2:xfetch2:${versions.fetch2}"
|
||||
|
||||
//Kovenant
|
||||
implementation("nl.komponents.kovenant:kovenant:3.3.0")
|
||||
implementation("nl.komponents.kovenant:kovenant-android:3.3.0")
|
||||
|
||||
//EventBus
|
||||
implementation("org.greenrobot:eventbus:3.2.0")
|
||||
|
||||
//Lib-SU
|
||||
implementation "com.github.topjohnwu.libsu:core:${versions.libsu}"
|
||||
|
||||
//Love <3
|
||||
api("com.gitlab.AuroraOSS:gplayapi:514f061739")
|
||||
}
|
||||
120
app/proguard-rules.pro
vendored
Normal file
120
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
# 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
|
||||
# ServiceLoader support
|
||||
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
|
||||
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
|
||||
|
||||
# Most of volatile fields are updated with AFU and should not be mangled
|
||||
-keepclassmembernames class kotlinx.** {
|
||||
volatile <fields>;
|
||||
}
|
||||
|
||||
# Same story for the standard library's SafeContinuation that also uses AtomicReferenceFieldUpdater
|
||||
-keepclassmembernames class kotlin.coroutines.SafeContinuation {
|
||||
volatile <fields>;
|
||||
}
|
||||
|
||||
# These classes are only required by kotlinx.coroutines.debug.AgentPremain, which is only loaded when
|
||||
# kotlinx-coroutines-core is used as a Java agent, so these are not needed in contexts where ProGuard is used.
|
||||
-dontwarn java.lang.instrument.ClassFileTransformer
|
||||
-dontwarn sun.misc.SignalHandler
|
||||
-dontwarn java.lang.instrument.Instrumentation
|
||||
-dontwarn sun.misc.Signal
|
||||
|
||||
# JSR 305 annotations are for embedding nullability information.
|
||||
-dontwarn javax.annotation.**
|
||||
|
||||
# A resource is loaded with a relative path so the package of this class must be preserved.
|
||||
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
|
||||
|
||||
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||
|
||||
# OkHttp platform used only on JVM and when Conscrypt dependency is available.
|
||||
-dontwarn okhttp3.internal.platform.ConscryptPlatform
|
||||
-dontwarn org.conscrypt.ConscryptHostnameVerifier
|
||||
|
||||
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||
|
||||
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
|
||||
# EnclosingMethod is required to use InnerClasses.
|
||||
-keepattributes Signature, InnerClasses, EnclosingMethod
|
||||
|
||||
# Retrofit does reflection on method and parameter annotations.
|
||||
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
|
||||
|
||||
# Retain service method parameters when optimizing.
|
||||
-keepclassmembers,allowshrinking,allowobfuscation interface * {
|
||||
@retrofit2.http.* <methods>;
|
||||
}
|
||||
|
||||
# Ignore annotation used for build tooling.
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
|
||||
|
||||
# Ignore JSR 305 annotations for embedding nullability information.
|
||||
-dontwarn javax.annotation.**
|
||||
|
||||
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
|
||||
-dontwarn kotlin.Unit
|
||||
|
||||
# Top-level functions that can only be used by Kotlin.
|
||||
-dontwarn retrofit2.KotlinExtensions
|
||||
-dontwarn retrofit2.KotlinExtensions$*
|
||||
|
||||
#Kovenant
|
||||
-dontwarn rx.internal.util.unsafe.**
|
||||
-dontwarn nl.komponents.kovenant.unsafe.**
|
||||
|
||||
-dontwarn okio.**
|
||||
-keep class com.google.**
|
||||
-dontwarn com.google.**
|
||||
-keep class com.google.gson.Gson {*;}
|
||||
|
||||
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
|
||||
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
|
||||
-if interface * { @retrofit2.http.* <methods>; }
|
||||
-keep,allowobfuscation interface <1>
|
||||
|
||||
#Event Bus
|
||||
-keepattributes *Annotation*
|
||||
-keepclassmembers class * {
|
||||
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||
}
|
||||
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
||||
|
||||
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
|
||||
<init>(java.lang.Throwable);
|
||||
}
|
||||
|
||||
-keepclassmembers enum * { *; }
|
||||
-keep class com.aurora.store.view.ui.preferences.**
|
||||
-dontwarn com.aurora.store.view.ui.preferences.**
|
||||
|
||||
-keepclassmembers class * {
|
||||
private <fields>;
|
||||
}
|
||||
|
||||
#GPlay API
|
||||
-keep public class com.aurora.gplayapi.** {
|
||||
*;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.aurora.aurorastore", appContext.packageName)
|
||||
}
|
||||
}
|
||||
128
app/src/main/AndroidManifest.xml
Normal file
128
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Aurora Store
|
||||
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
~
|
||||
~ Aurora Store 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 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Aurora Store 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.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.aurora.store">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
<uses-permission
|
||||
android:name="android.permission.INSTALL_PACKAGES"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission
|
||||
android:name="android.permission.DELETE_PACKAGES"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" /> <!-- MIUI -->
|
||||
<uses-permission android:name="com.miui.securitycenter.permission.GLOBAL_PACKAGEINSTALLER" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
android:required="false" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
|
||||
<application
|
||||
android:name=".AuroraApplication"
|
||||
android:allowBackup="true"
|
||||
android:banner="@drawable/ic_launcher_background"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="m">
|
||||
|
||||
<activity
|
||||
android:name=".view.ui.onboarding.OnboardingActivity"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".view.ui.splash.SplashActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:launchMode="singleTask" />
|
||||
|
||||
<activity android:name=".view.ui.search.SearchSuggestionActivity" />
|
||||
<activity android:name=".view.ui.search.SearchResultsActivity" />
|
||||
<activity android:name=".view.ui.commons.StreamBrowseActivity" />
|
||||
<activity android:name=".view.ui.sale.AppSalesActivity" />
|
||||
<activity android:name=".view.ui.details.AppDetailsActivity" />
|
||||
<activity android:name=".view.ui.details.ScreenshotActivity" />
|
||||
<activity android:name=".view.ui.all.AppsGamesActivity" />
|
||||
<activity android:name=".view.ui.commons.CategoryBrowseActivity" />
|
||||
<activity android:name=".view.ui.details.DetailsMoreActivity" />
|
||||
<activity android:name=".view.ui.details.DetailsReviewActivity" />
|
||||
<activity android:name=".view.ui.downloads.DownloadActivity" />
|
||||
<activity android:name=".view.ui.account.GoogleActivity" />
|
||||
<activity android:name=".view.ui.spoof.SpoofActivity" />
|
||||
<activity android:name=".view.ui.account.AccountActivity" />
|
||||
<activity android:name=".view.ui.details.DetailsExodusActivity" />
|
||||
<activity android:name=".view.ui.details.DevAppsActivity" />
|
||||
<activity android:name=".view.ui.commons.BlacklistActivity" />
|
||||
<activity android:name=".view.ui.preferences.SettingsActivity" />
|
||||
<activity android:name=".view.ui.about.AboutActivity" />
|
||||
|
||||
<service android:name=".data.service.NotificationService" />
|
||||
<service android:name=".data.installer.InstallerService" />
|
||||
<service
|
||||
android:name="com.novoda.merlin.MerlinService"
|
||||
android:exported="false" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/paths" />
|
||||
</provider>
|
||||
|
||||
<receiver android:name=".data.receiver.PackageManagerReceiver" />
|
||||
<receiver android:name=".data.receiver.DownloadResumeReceiver" />
|
||||
<receiver android:name=".data.receiver.DownloadPauseReceiver" />
|
||||
<receiver android:name=".data.receiver.DownloadCancelReceiver" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2016 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package com.aurora.services;
|
||||
|
||||
interface IPrivilegedCallback {
|
||||
void handleResult(
|
||||
in String packageName,
|
||||
in int returnCode
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2016 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package com.aurora.services;
|
||||
|
||||
import com.aurora.services.IPrivilegedCallback;
|
||||
|
||||
interface IPrivilegedService {
|
||||
|
||||
boolean hasPrivilegedPermissions();
|
||||
|
||||
oneway void installPackage(
|
||||
in String packageName,
|
||||
in Uri uri,
|
||||
in int flags,
|
||||
in String installerPackageName,
|
||||
in IPrivilegedCallback callback
|
||||
);
|
||||
|
||||
oneway void installSplitPackage(
|
||||
in String packageName,
|
||||
in List<Uri> uriList,
|
||||
in int flags,
|
||||
in String installerPackageName,
|
||||
in IPrivilegedCallback callback
|
||||
);
|
||||
|
||||
oneway void deletePackage(
|
||||
in String packageName,
|
||||
in int flags,
|
||||
in IPrivilegedCallback callback
|
||||
);
|
||||
}
|
||||
50
app/src/main/assets/accent.json
Executable file
50
app/src/main/assets/accent.json
Executable file
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"accent": "#6C63FF"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"accent": "#FF00FF"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"accent": "#F50057"
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"accent": "#F9A826"
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"accent": "#49A942"
|
||||
},
|
||||
{
|
||||
"id": "6",
|
||||
"accent": "#6633cc"
|
||||
},
|
||||
{
|
||||
"id": "7",
|
||||
"accent": "#52565e"
|
||||
},
|
||||
{
|
||||
"id": "8",
|
||||
"accent": "#ee70a6"
|
||||
},
|
||||
{
|
||||
"id": "9",
|
||||
"accent": "#b5c327"
|
||||
},
|
||||
{
|
||||
"id": "10",
|
||||
"accent": "#f38654"
|
||||
},
|
||||
{
|
||||
"id": "11",
|
||||
"accent": "#61A7E0"
|
||||
},
|
||||
{
|
||||
"id": "12",
|
||||
"accent": "#7289da"
|
||||
}
|
||||
]
|
||||
37
app/src/main/assets/dash.json
Executable file
37
app/src/main/assets/dash.json
Executable file
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"id": "0",
|
||||
"title": "FAQs",
|
||||
"subtitle": "Have questions? Find out the answers.",
|
||||
"icon": "ic_faq",
|
||||
"url": "https://gitlab.com/AuroraOSS/AuroraStore"
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"title": "Source code",
|
||||
"icon": "ic_code",
|
||||
"subtitle": "Find out what's inside.",
|
||||
"url": "https://gitlab.com/AuroraOSS/AuroraStore/-/blob/master"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"title": "License",
|
||||
"subtitle": "Yes we do have one ;)",
|
||||
"icon": "ic_license",
|
||||
"url": "https://gitlab.com/AuroraOSS/AuroraStore/-/raw/master/LICENSE"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"title": "Privacy",
|
||||
"subtitle": "Find out if we have your nudes :p",
|
||||
"icon": "ic_privacy",
|
||||
"url": "https://gitlab.com/AuroraOSS/AuroraStore/-/raw/master/PRIVACY"
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"title": "Disclaimer",
|
||||
"subtitle": "Hold your own beer!",
|
||||
"icon": "ic_disclaimer",
|
||||
"url": "https://gitlab.com/AuroraOSS/AuroraStore/-/raw/master/DISCLAIMER"
|
||||
}
|
||||
]
|
||||
2724
app/src/main/assets/exodus_trackers.json
Executable file
2724
app/src/main/assets/exodus_trackers.json
Executable file
File diff suppressed because it is too large
Load Diff
28
app/src/main/assets/installers.json
Executable file
28
app/src/main/assets/installers.json
Executable file
@@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"id": "0",
|
||||
"title": "Session installer",
|
||||
"subtitle": "Session based installer for bundled/split APKs",
|
||||
"description": "Best suited for devices running Android 5.0+.",
|
||||
"url": "https://developer.android.com/reference/android/content/pm/PackageInstaller.Session"
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"title": "Native installer",
|
||||
"subtitle": "Intent based installer, available on all devices",
|
||||
"description": "Best suited for devices running below Android 4.4 or OEM modified ROMs like MIUI, One-UI.",
|
||||
"url": "https://developer.android.com/reference/android/content/Intent#setDataAndType"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"title": "Root installer",
|
||||
"subtitle": "Installer for background installations",
|
||||
"description": "Requires root, supports all Android versions."
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"title": "Aurora Service",
|
||||
"subtitle": "Installer for background installations",
|
||||
"description": "Requires Aurora Services to be installed as system app."
|
||||
}
|
||||
]
|
||||
32
app/src/main/assets/themes.json
Executable file
32
app/src/main/assets/themes.json
Executable file
@@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"id": "0",
|
||||
"title": "System",
|
||||
"subtitle": "Follow system themes."
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"title": "Light",
|
||||
"subtitle": "White UI must die, may slap on your face at night."
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"title": "Dark",
|
||||
"subtitle": "As dark as your humour, suitable for night-owls."
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"title": "Pitch Black",
|
||||
"subtitle": "The black, that matters."
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"title": "Dark-X",
|
||||
"subtitle": "The dark, that looks cool?"
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"title": "Disskord",
|
||||
"subtitle": "Kanged from discord"
|
||||
}
|
||||
]
|
||||
BIN
app/src/main/ic_launcher-playstore.png
Normal file
BIN
app/src/main/ic_launcher-playstore.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
51
app/src/main/java/com/aurora/Constants.kt
Normal file
51
app/src/main/java/com/aurora/Constants.kt
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora
|
||||
|
||||
object Constants {
|
||||
const val INT_EXTRA = "INT_EXTRA"
|
||||
const val FLOAT_EXTRA = "FLOAT_EXTRA"
|
||||
const val STRING_APP = "STRING_APP"
|
||||
const val STRING_EXTRA = "STRING_EXTRA"
|
||||
const val BROWSE_EXTRA = "BROWSE_EXTRA"
|
||||
|
||||
const val FETCH_GROUP_ID = "FETCH_GROUP_ID"
|
||||
|
||||
const val CONNECTIVITY_CHECK_URL = "https://connectivitycheck.android.com/generate_204"
|
||||
const val EXODUS_BASE_URL = "https://reports.exodus-privacy.eu.org/api/search/"
|
||||
const val EXODUS_REPORT_URL = "https://reports.exodus-privacy.eu.org/reports/"
|
||||
const val SHARE_URL = "http://play.google.com/store/apps/details?id="
|
||||
|
||||
const val NOTIFICATION_CHANNEL_ALERT = "NOTIFICATION_CHANNEL_ALERT"
|
||||
const val NOTIFICATION_CHANNEL_GENERAL = "NOTIFICATION_CHANNEL_GENERAL"
|
||||
|
||||
const val URL_DISPENSER = "http://goolag.store:1337/api/auth"
|
||||
|
||||
//ACCOUNTS
|
||||
const val ACCOUNT_SIGNED_IN = "ACCOUNT_SIGNED_IN"
|
||||
const val ACCOUNT_SIGNED_TIMESTAMP = "ACCOUNT_SIGNED_TIMESTAMP"
|
||||
const val ACCOUNT_TYPE = "ACCOUNT_TYPE"
|
||||
const val ACCOUNT_EMAIL_PLAIN = "ACCOUNT_EMAIL_PLAIN"
|
||||
const val ACCOUNT_AAS_PLAIN = "ACCOUNT_AAS_PLAIN"
|
||||
|
||||
const val PAGE_TYPE = "PAGE_TYPE"
|
||||
const val TOP_CHART_TYPE = "TOP_CHART_TYPE"
|
||||
const val TOP_CHART_CATEGORY = "TOP_CHART_CATEGORY"
|
||||
}
|
||||
78
app/src/main/java/com/aurora/store/AuroraApplication.kt
Normal file
78
app/src/main/java/com/aurora/store/AuroraApplication.kt
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
import com.aurora.store.data.providers.NetworkProvider
|
||||
import com.aurora.store.data.receiver.PackageManagerReceiver
|
||||
import com.aurora.store.data.service.NotificationService
|
||||
import com.aurora.store.util.CommonUtil
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import com.tonyodev.fetch2.Fetch
|
||||
import nl.komponents.kovenant.android.startKovenant
|
||||
import nl.komponents.kovenant.android.stopKovenant
|
||||
|
||||
class AuroraApplication : MultiDexApplication() {
|
||||
|
||||
private lateinit var fetch: Fetch
|
||||
private lateinit var packageManagerReceiver: PackageManagerReceiver
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||
|
||||
NotificationService.startService(this)
|
||||
|
||||
fetch = DownloadManager.with(this).fetch
|
||||
|
||||
packageManagerReceiver = object : PackageManagerReceiver() {
|
||||
|
||||
}
|
||||
|
||||
//Register broadcast receiver for package install/uninstall
|
||||
registerReceiver(packageManagerReceiver, PackageUtil.getFilter())
|
||||
|
||||
NetworkProvider
|
||||
.with(this)
|
||||
.bind()
|
||||
|
||||
startKovenant()
|
||||
|
||||
CommonUtil.cleanupInstallationSessions(applicationContext)
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
NetworkProvider
|
||||
.with(this)
|
||||
.unbind()
|
||||
stopKovenant()
|
||||
super.onTerminate()
|
||||
}
|
||||
|
||||
override fun onLowMemory() {
|
||||
NetworkProvider
|
||||
.with(this)
|
||||
.unbind()
|
||||
super.onLowMemory()
|
||||
}
|
||||
}
|
||||
53
app/src/main/java/com/aurora/store/AuroraGlide.kt
Normal file
53
app/src/main/java/com/aurora/store/AuroraGlide.kt
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import com.bumptech.glide.GlideBuilder
|
||||
import com.bumptech.glide.annotation.GlideModule
|
||||
import com.bumptech.glide.load.DecodeFormat
|
||||
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
|
||||
import com.bumptech.glide.load.engine.cache.LruResourceCache
|
||||
import com.bumptech.glide.module.AppGlideModule
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.signature.ObjectKey
|
||||
|
||||
@GlideModule
|
||||
class AuroraGlide : AppGlideModule() {
|
||||
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
||||
val memoryCacheSizeBytes = 1024 * 1024 * 50
|
||||
builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong()))
|
||||
builder.setDiskCache(InternalCacheDiskCacheFactory(context, memoryCacheSizeBytes.toLong()))
|
||||
builder.setDefaultRequestOptions(requestOptions(context))
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun requestOptions(context: Context): RequestOptions {
|
||||
return RequestOptions()
|
||||
.signature(ObjectKey(System.currentTimeMillis() / (24 * 60 * 60 * 1000)))
|
||||
.centerCrop()
|
||||
.encodeFormat(Bitmap.CompressFormat.PNG)
|
||||
.encodeQuality(60)
|
||||
.format(DecodeFormat.PREFER_ARGB_8888)
|
||||
.skipMemoryCache(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
25
app/src/main/java/com/aurora/store/Enumerations.kt
Normal file
25
app/src/main/java/com/aurora/store/Enumerations.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store
|
||||
|
||||
enum class AccountType {
|
||||
ANONYMOUS,
|
||||
GOOGLE
|
||||
}
|
||||
243
app/src/main/java/com/aurora/store/MainActivity.kt
Normal file
243
app/src/main/java/com/aurora/store/MainActivity.kt
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.navigation.ui.NavigationUI
|
||||
import com.aurora.gplayapi.data.models.AuthData
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.databinding.ActivityMainBinding
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.ViewUtil
|
||||
import com.aurora.store.util.ViewUtil.getStyledAttribute
|
||||
import com.aurora.store.util.extensions.isQAndAbove
|
||||
import com.aurora.store.util.extensions.load
|
||||
import com.aurora.store.util.extensions.open
|
||||
import com.aurora.store.view.ui.about.AboutActivity
|
||||
import com.aurora.store.view.ui.account.AccountActivity
|
||||
import com.aurora.store.view.ui.all.AppsGamesActivity
|
||||
import com.aurora.store.view.ui.commons.BaseActivity
|
||||
import com.aurora.store.view.ui.commons.BlacklistActivity
|
||||
import com.aurora.store.view.ui.downloads.DownloadActivity
|
||||
import com.aurora.store.view.ui.preferences.SettingsActivity
|
||||
import com.aurora.store.view.ui.sale.AppSalesActivity
|
||||
import com.aurora.store.view.ui.search.SearchSuggestionActivity
|
||||
import com.aurora.store.view.ui.spoof.SpoofActivity
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.livinglifetechway.quickpermissions_kotlin.runWithPermissions
|
||||
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
|
||||
private lateinit var B: ActivityMainBinding
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var authData: AuthData
|
||||
|
||||
private var lastBackPressed = 0L
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private fun matchDestination(
|
||||
@NonNull destination: NavDestination?,
|
||||
@IdRes destId: Int
|
||||
): Boolean {
|
||||
var currentDestination = destination
|
||||
while (currentDestination?.id != destId && currentDestination?.parent != null) {
|
||||
currentDestination = currentDestination.parent
|
||||
}
|
||||
return currentDestination?.id == destId
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
B = ActivityMainBinding.inflate(layoutInflater)
|
||||
|
||||
setContentView(B.root)
|
||||
|
||||
authData = AuthProvider.with(this).getAuthData()
|
||||
|
||||
attachToolbar()
|
||||
attachNavigation()
|
||||
attachDrawer()
|
||||
attachSearch()
|
||||
|
||||
checkPermission()
|
||||
}
|
||||
|
||||
private fun checkPermission() = runWithPermissions(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) {
|
||||
Log.i("External Storage Access Available")
|
||||
|
||||
if (isQAndAbove()) {
|
||||
//pickExternalFileDir()
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachToolbar() {
|
||||
B.viewToolbar.imgActionPrimary.setOnClickListener {
|
||||
B.drawerLayout.openDrawer(GravityCompat.START, true)
|
||||
}
|
||||
|
||||
B.viewToolbar.imgActionSecondary.setOnClickListener {
|
||||
val userAppIntent = Intent(this, DownloadActivity::class.java)
|
||||
startActivity(userAppIntent, ViewUtil.getEmptyActivityBundle(this))
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachSearch() {
|
||||
B.searchFab.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(this, SearchSuggestionActivity::class.java),
|
||||
ViewUtil.getEmptyActivityBundle(this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachNavigation() {
|
||||
val bottomNavigationView: BottomNavigationView = B.navView
|
||||
navController = Navigation.findNavController(this, R.id.nav_host_fragment)
|
||||
|
||||
val backGroundColor = getStyledAttribute(this, android.R.attr.colorBackground)
|
||||
bottomNavigationView.setBackgroundColor(ColorUtils.setAlphaComponent(backGroundColor, 245))
|
||||
|
||||
|
||||
bottomNavigationView.setOnNavigationItemSelectedListener { item ->
|
||||
if (item.itemId == bottomNavigationView.selectedItemId)
|
||||
return@setOnNavigationItemSelectedListener false
|
||||
NavigationUI.onNavDestinationSelected(item, navController)
|
||||
true
|
||||
}
|
||||
|
||||
navController.addOnDestinationChangedListener { _: NavController?, destination: NavDestination?, _: Bundle? ->
|
||||
val menu: Menu = bottomNavigationView.menu
|
||||
val size: Int = menu.size()
|
||||
for (i in 0 until size) {
|
||||
val item: MenuItem = menu.getItem(i)
|
||||
if (matchDestination(destination, item.itemId)) {
|
||||
item.isChecked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachDrawer() {
|
||||
val headerView: View = B.navigation.getHeaderView(0)
|
||||
|
||||
headerView.let {
|
||||
it.findViewById<ImageView>(R.id.img)?.load(R.mipmap.ic_launcher) {
|
||||
transform(RoundedCorners(8))
|
||||
}
|
||||
it.findViewById<TextView>(R.id.txt_name)?.text = getString(R.string.app_name)
|
||||
it.findViewById<TextView>(R.id.txt_email)?.text =
|
||||
("v${BuildConfig.VERSION_NAME}.${BuildConfig.VERSION_CODE}")
|
||||
}
|
||||
|
||||
B.navigation.setNavigationItemSelectedListener { item: MenuItem ->
|
||||
when (item.itemId) {
|
||||
R.id.menu_apps_games -> {
|
||||
open(AppsGamesActivity::class.java)
|
||||
}
|
||||
R.id.menu_apps_sale -> {
|
||||
open(AppSalesActivity::class.java)
|
||||
}
|
||||
R.id.menu_blacklist_manager -> {
|
||||
open(BlacklistActivity::class.java)
|
||||
}
|
||||
R.id.menu_download_manager -> {
|
||||
open(DownloadActivity::class.java)
|
||||
}
|
||||
R.id.menu_spoof_manager -> {
|
||||
open(SpoofActivity::class.java)
|
||||
}
|
||||
R.id.menu_account_manager -> {
|
||||
open(AccountActivity::class.java)
|
||||
}
|
||||
R.id.menu_settings -> {
|
||||
open(SettingsActivity::class.java)
|
||||
}
|
||||
R.id.menu_about -> {
|
||||
open(AboutActivity::class.java)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
return navController.navigateUp()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (!navController.navigateUp()) {
|
||||
if (lastBackPressed + 1000 > System.currentTimeMillis()) {
|
||||
super.onBackPressed()
|
||||
} else {
|
||||
lastBackPressed = System.currentTimeMillis()
|
||||
Toast.makeText(this, "Click twice to exit", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConnected() {
|
||||
hideNetworkConnectivitySheet()
|
||||
}
|
||||
|
||||
override fun onDisconnected() {
|
||||
showNetworkConnectivitySheet()
|
||||
}
|
||||
|
||||
override fun onReconnected() {
|
||||
|
||||
}
|
||||
|
||||
private fun pickExternalFileDir() {
|
||||
val getContentIntent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
getContentIntent.type = "*/*"
|
||||
getContentIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
getContentIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true)
|
||||
getContentIntent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
startActivityForResult(
|
||||
Intent.createChooser(
|
||||
getContentIntent,
|
||||
"Aurora Store - External Storage Access"
|
||||
), 1337
|
||||
)
|
||||
}
|
||||
}
|
||||
36
app/src/main/java/com/aurora/store/data/SingletonHolder.kt
Normal file
36
app/src/main/java/com/aurora/store/data/SingletonHolder.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data
|
||||
|
||||
open class SingletonHolder<out T, in A>(private val constructor: (A) -> T) {
|
||||
|
||||
@Volatile
|
||||
private var instance: T? = null
|
||||
|
||||
fun with(arg: A): T {
|
||||
return when {
|
||||
instance != null -> instance!!
|
||||
else -> synchronized(this) {
|
||||
if (instance == null) instance = constructor(arg)
|
||||
instance!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
app/src/main/java/com/aurora/store/data/State.kt
Normal file
44
app/src/main/java/com/aurora/store/data/State.kt
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data
|
||||
|
||||
|
||||
sealed class ViewState {
|
||||
object Loading : ViewState()
|
||||
object Empty : ViewState()
|
||||
data class Error(val error: String?) : ViewState()
|
||||
data class Status(val status: String?) : ViewState()
|
||||
data class Success<T>(val data: T) : ViewState()
|
||||
}
|
||||
|
||||
sealed class RequestState {
|
||||
object Init : RequestState()
|
||||
object Pending : RequestState()
|
||||
object Complete : RequestState()
|
||||
}
|
||||
|
||||
sealed class AuthState {
|
||||
object Available : AuthState()
|
||||
object Unavailable : AuthState()
|
||||
object SignedIn : AuthState()
|
||||
object SignedOut : AuthState()
|
||||
object Valid : AuthState()
|
||||
data class Status(val status: String?) : AuthState()
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.downloader
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.Constants
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.tonyodev.fetch2.*
|
||||
import com.tonyodev.fetch2core.DefaultStorageResolver
|
||||
import com.tonyodev.fetch2core.getFileTempDir
|
||||
|
||||
class DownloadManager private constructor(var context: Context) {
|
||||
|
||||
companion object : SingletonHolder<DownloadManager, Context>(::DownloadManager)
|
||||
|
||||
var fetch: Fetch
|
||||
|
||||
init {
|
||||
fetch = Fetch.getInstance(getFetchConfiguration(context))
|
||||
}
|
||||
|
||||
fun getFetchInstance(): Fetch {
|
||||
return fetch
|
||||
}
|
||||
|
||||
private fun getFetchConfiguration(context: Context): FetchConfiguration {
|
||||
var maxActive = Preferences.getInteger(context, Preferences.PREFERENCE_DOWNLOAD_ACTIVE)
|
||||
if (maxActive == 0)
|
||||
maxActive = 1
|
||||
return FetchConfiguration.Builder(context)
|
||||
.setDownloadConcurrentLimit(maxActive)
|
||||
.enableLogging(BuildConfig.DEBUG)
|
||||
.enableHashCheck(true)
|
||||
.enableFileExistChecks(true)
|
||||
.enableRetryOnNetworkGain(true)
|
||||
.enableAutoStart(true)
|
||||
.setInternetAccessUrlCheck(Constants.CONNECTIVITY_CHECK_URL)
|
||||
.setAutoRetryMaxAttempts(3)
|
||||
.setProgressReportingInterval(3000)
|
||||
.setNamespace(BuildConfig.APPLICATION_ID)
|
||||
.setStorageResolver(DefaultStorageResolver(context, getFileTempDir(context)))
|
||||
.build()
|
||||
}
|
||||
|
||||
fun isDownloading(fetchGroup: FetchGroup): Boolean {
|
||||
return fetchGroup.downloadingDownloads.isNotEmpty()
|
||||
|| fetchGroup.queuedDownloads.isNotEmpty()
|
||||
|| fetchGroup.addedDownloads.isNotEmpty()
|
||||
}
|
||||
|
||||
fun isCanceled(fetchGroup: FetchGroup): Boolean {
|
||||
return fetchGroup.cancelledDownloads.isNotEmpty()
|
||||
|| fetchGroup.removedDownloads.isNotEmpty()
|
||||
|| fetchGroup.deletedDownloads.isNotEmpty()
|
||||
}
|
||||
|
||||
fun updateOngoingDownloads(
|
||||
fetch: Fetch, packageList: MutableList<String?>, download: Download,
|
||||
fetchListener: FetchListener?
|
||||
) {
|
||||
if (packageList.contains(download.tag)) {
|
||||
val packageName = download.tag
|
||||
if (packageName != null) {
|
||||
fetch.deleteGroup(packageName.hashCode())
|
||||
packageList.remove(packageName)
|
||||
}
|
||||
}
|
||||
if (packageList.size == 0) {
|
||||
fetch.removeListener(fetchListener!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.downloader
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.Constants
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
import com.aurora.store.util.PathUtil
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.tonyodev.fetch2.EnqueueAction
|
||||
import com.tonyodev.fetch2.NetworkType
|
||||
import com.tonyodev.fetch2.Request
|
||||
import com.tonyodev.fetch2core.Extras
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
private inline fun Request.attachMetaData(app: App) {
|
||||
apply {
|
||||
groupId = app.id
|
||||
tag = app.packageName
|
||||
enqueueAction = EnqueueAction.UPDATE_ACCORDINGLY
|
||||
networkType = NetworkType.ALL
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun Request.attachExtra(app: App) {
|
||||
val stringMap: MutableMap<String, String> = mutableMapOf()
|
||||
val gson = GsonBuilder()
|
||||
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
|
||||
.create()
|
||||
stringMap[Constants.STRING_EXTRA] = gson.toJson(app)
|
||||
apply {
|
||||
extras = Extras(stringMap)
|
||||
}
|
||||
}
|
||||
|
||||
object RequestBuilder {
|
||||
|
||||
fun buildRequest(context: Context, app: App, file: File): Request {
|
||||
val fileName = when (file.type) {
|
||||
File.FileType.BASE,
|
||||
File.FileType.SPLIT -> PathUtil.getApkDownloadFile(context, app, file)
|
||||
File.FileType.OBB,
|
||||
File.FileType.PATCH -> PathUtil.getObbDownloadFile(context, app, file)
|
||||
}
|
||||
return Request(file.url, fileName).apply {
|
||||
attachMetaData(app)
|
||||
attachExtra(app)
|
||||
}
|
||||
}
|
||||
}
|
||||
31
app/src/main/java/com/aurora/store/data/event/BusEvent.kt
Normal file
31
app/src/main/java/com/aurora/store/data/event/BusEvent.kt
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.event
|
||||
|
||||
sealed class BusEvent {
|
||||
data class InstallEvent(var packageName: String, var error: String = String()) : BusEvent()
|
||||
data class UninstallEvent(var packageName: String, var error: String = String()) : BusEvent()
|
||||
data class Blacklisted(var packageName: String, var error: String = String()) : BusEvent()
|
||||
data class GoogleAAS(
|
||||
var success: Boolean,
|
||||
var email: String = String(),
|
||||
var aasToken: String = String()
|
||||
) : BusEvent()
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID
|
||||
|
||||
open class AppInstaller private constructor(var context: Context) {
|
||||
|
||||
companion object : SingletonHolder<AppInstaller, Context>(::AppInstaller)
|
||||
|
||||
fun getPreferredInstaller(): IInstaller {
|
||||
val prefValue = Preferences.getInteger(
|
||||
context,
|
||||
PREFERENCE_INSTALLER_ID
|
||||
)
|
||||
|
||||
return when (prefValue) {
|
||||
1 -> NativeInstaller(context)
|
||||
2 -> RootInstaller(context)
|
||||
3 -> ServiceInstaller(context)
|
||||
else -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
SessionInstaller(context)
|
||||
} else {
|
||||
NativeInstaller(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
interface IInstaller {
|
||||
fun install(packageName: String, files: List<Any>)
|
||||
fun uninstall(packageName: String)
|
||||
|
||||
fun clearQueue()
|
||||
fun isAlreadyQueued(packageName: String): Boolean
|
||||
fun removeFromInstallQueue(packageName: String)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.content.FileProvider
|
||||
import com.aurora.store.BuildConfig
|
||||
import java.io.File
|
||||
|
||||
abstract class InstallerBase(protected var context: Context) : IInstaller {
|
||||
|
||||
private val enqueuedInstalls: MutableSet<String> = mutableSetOf()
|
||||
|
||||
override fun clearQueue() {
|
||||
enqueuedInstalls.clear()
|
||||
}
|
||||
|
||||
override fun isAlreadyQueued(packageName: String): Boolean {
|
||||
return enqueuedInstalls.contains(packageName)
|
||||
}
|
||||
|
||||
override fun removeFromInstallQueue(packageName: String) {
|
||||
enqueuedInstalls.remove(packageName)
|
||||
}
|
||||
|
||||
override fun uninstall(packageName: String) {
|
||||
val uri = Uri.fromParts("package", packageName, null)
|
||||
val intent = Intent().apply {
|
||||
data = uri
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
intent.action = Intent.ACTION_DELETE
|
||||
} else {
|
||||
intent.action = Intent.ACTION_UNINSTALL_PACKAGE
|
||||
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
|
||||
}
|
||||
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
open fun getUri(file: File): Uri {
|
||||
return FileProvider.getUriForFile(
|
||||
context,
|
||||
"${BuildConfig.APPLICATION_ID}.fileProvider",
|
||||
file
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.annotation.RequiresApi
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
|
||||
class InstallerService : Service() {
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1)
|
||||
val packageName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)
|
||||
|
||||
//Send broadcast for the installation status of the package
|
||||
sendStatusBroadcast(status, packageName)
|
||||
|
||||
//Launch user confirmation activity
|
||||
if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) {
|
||||
val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
|
||||
confirmationIntent!!.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
|
||||
confirmationIntent.putExtra(
|
||||
Intent.EXTRA_INSTALLER_PACKAGE_NAME,
|
||||
"com.android.vending"
|
||||
)
|
||||
confirmationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
try {
|
||||
startActivity(confirmationIntent)
|
||||
} catch (e: Exception) {
|
||||
sendStatusBroadcast(PackageInstaller.STATUS_FAILURE, packageName)
|
||||
}
|
||||
}
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
private fun sendStatusBroadcast(status: Int, packageName: String?) {
|
||||
if (StringUtils.isNotEmpty(packageName)) {
|
||||
val statusIntent = Intent(ACTION_SESSION_INSTALLER)
|
||||
statusIntent.putExtra(PackageInstaller.EXTRA_STATUS, status)
|
||||
statusIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName)
|
||||
sendBroadcast(statusIntent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ACTION_SESSION_INSTALLER = "ACTION_SESSION_INSTALLER"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import com.aurora.store.util.Log
|
||||
import java.io.File
|
||||
|
||||
class NativeInstaller(context: Context) : InstallerBase(context) {
|
||||
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
} else {
|
||||
files.map {
|
||||
when (it) {
|
||||
is File -> it
|
||||
is String -> File(it)
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}.forEach {
|
||||
xInstall(packageName, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun xInstall(packageName: String, file: File) {
|
||||
val intent: Intent
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
intent = Intent(Intent.ACTION_INSTALL_PACKAGE)
|
||||
intent.data = getUri(file)
|
||||
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
} else {
|
||||
intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
|
||||
intent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, "com.android.vending")
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.extensions.isLAndAbove
|
||||
import com.aurora.store.util.extensions.toast
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class RootInstaller(context: Context) : InstallerBase(context) {
|
||||
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
} else {
|
||||
if (Shell.getShell().isRoot) {
|
||||
files.map {
|
||||
when (it) {
|
||||
is File -> it
|
||||
is String -> File(it)
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}.let {
|
||||
if (isLAndAbove())
|
||||
xInstall(packageName, it)
|
||||
else
|
||||
xInstallLegacy(packageName, it)
|
||||
}
|
||||
} else {
|
||||
context.toast(context.getString(R.string.installer_root_unavailable))
|
||||
Log.e(" >>>>>>>>>>>>>>>>>>>>>>>>>> NO ROOT ACCESS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun xInstall(packageName: String, files: List<File>) {
|
||||
var totalSize = 0
|
||||
|
||||
for (file in files)
|
||||
totalSize += file.length().toInt()
|
||||
|
||||
val result: Shell.Result =
|
||||
Shell.su("pm install-create -i com.android.vending --user 0 -r -S $totalSize")
|
||||
.exec()
|
||||
|
||||
val response = result.out
|
||||
|
||||
val sessionIdPattern = Pattern.compile("(\\d+)")
|
||||
val sessionIdMatcher = sessionIdPattern.matcher(response[0])
|
||||
val found = sessionIdMatcher.find()
|
||||
|
||||
if (found) {
|
||||
val sessionId = sessionIdMatcher.group(1).toInt()
|
||||
if (Shell.getShell().isRoot) {
|
||||
for (file in files) {
|
||||
Shell.su("cat \"${file.absoluteFile}\" | pm install-write -S ${file.length()} $sessionId \"${file.name}\"")
|
||||
.exec()
|
||||
}
|
||||
|
||||
Shell.su("pm install-commit $sessionId").exec()
|
||||
} else {
|
||||
removeFromInstallQueue(packageName)
|
||||
}
|
||||
} else {
|
||||
removeFromInstallQueue(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun xInstallLegacy(packageName: String, files: List<File>) {
|
||||
if (Shell.getShell().isRoot) {
|
||||
Shell.su("pm install -i com.android.vending --user 0 \"${files[0].name}\"").exec()
|
||||
} else {
|
||||
removeFromInstallQueue(packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.RemoteException
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.aurora.services.IPrivilegedCallback
|
||||
import com.aurora.services.IPrivilegedService
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.util.Log
|
||||
import java.io.File
|
||||
|
||||
class ServiceInstaller(context: Context) : InstallerBase(context) {
|
||||
|
||||
companion object {
|
||||
const val ACTION_INSTALL_REPLACE_EXISTING = 2
|
||||
const val PRIVILEGED_EXTENSION_PACKAGE_NAME = "com.aurora.services"
|
||||
const val PRIVILEGED_EXTENSION_SERVICE_INTENT = "com.aurora.services.IPrivilegedService"
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
} else {
|
||||
Log.i("Received service install request for $packageName")
|
||||
val uriList = files.map {
|
||||
when (it) {
|
||||
is File -> getUri(it)
|
||||
is String -> getUri(File(it))
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xInstall(packageName, uriList)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private fun xInstall(packageName: String, uriList: List<Uri>) {
|
||||
|
||||
val serviceConnection = object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName, binder: IBinder) {
|
||||
val service = IPrivilegedService.Stub.asInterface(binder)
|
||||
val callback = object : IPrivilegedCallback.Stub() {
|
||||
override fun handleResult(packageName: String, returnCode: Int) {
|
||||
removeFromInstallQueue(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
service.installSplitPackage(
|
||||
packageName,
|
||||
uriList,
|
||||
ACTION_INSTALL_REPLACE_EXISTING,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
callback
|
||||
)
|
||||
} catch (e: RemoteException) {
|
||||
removeFromInstallQueue(packageName)
|
||||
Log.e("Failed to connect Aurora Services")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName) {
|
||||
removeFromInstallQueue(packageName)
|
||||
Log.e("Disconnected from Aurora Services")
|
||||
}
|
||||
}
|
||||
|
||||
val intent = Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT)
|
||||
intent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME)
|
||||
|
||||
context.bindService(
|
||||
intent,
|
||||
serviceConnection,
|
||||
Context.BIND_AUTO_CREATE
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInstaller.SessionParams
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.FileProvider
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.util.Log
|
||||
import org.apache.commons.io.IOUtils
|
||||
import java.io.File
|
||||
|
||||
class SessionInstaller(context: Context) : InstallerBase(context) {
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
} else {
|
||||
Log.i("Received service install request for $packageName")
|
||||
val uriList = files.map {
|
||||
when (it) {
|
||||
is File -> getUri(it)
|
||||
is String -> getUri(File(it))
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xInstall(packageName, uriList)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private fun xInstall(packageName: String, uriList: List<Uri>) {
|
||||
val packageInstaller = context.packageManager.packageInstaller
|
||||
val sessionParams = SessionParams(SessionParams.MODE_FULL_INSTALL)
|
||||
val sessionId = packageInstaller.createSession(sessionParams)
|
||||
val session = packageInstaller.openSession(sessionId)
|
||||
|
||||
try {
|
||||
|
||||
Log.i("Writing splits to session for $packageName")
|
||||
var apkId = 1
|
||||
for (uri in uriList) {
|
||||
val inputStream = context.contentResolver.openInputStream(uri)
|
||||
val outputStream = session.openWrite(
|
||||
"${packageName}_${apkId++}",
|
||||
0,
|
||||
-1
|
||||
)
|
||||
|
||||
IOUtils.copy(inputStream, outputStream)
|
||||
|
||||
session.fsync(outputStream)
|
||||
|
||||
IOUtils.close(inputStream)
|
||||
IOUtils.close(outputStream)
|
||||
}
|
||||
|
||||
val intent = Intent(context, InstallerService::class.java)
|
||||
val pendingIntent = PendingIntent.getService(
|
||||
context,
|
||||
sessionId,
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
Log.i("Starting install session for $packageName")
|
||||
session.commit(pendingIntent.intentSender)
|
||||
session.close()
|
||||
} catch (e: Exception) {
|
||||
session.abandon()
|
||||
removeFromInstallQueue(packageName)
|
||||
Log.e("Failed to install $packageName : %s", e.message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUri(file: File): Uri {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${BuildConfig.APPLICATION_ID}.fileProvider",
|
||||
file
|
||||
)
|
||||
|
||||
uri.apply {
|
||||
context.grantUriPermission(
|
||||
BuildConfig.APPLICATION_ID,
|
||||
uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
|
||||
return uri
|
||||
}
|
||||
}
|
||||
36
app/src/main/java/com/aurora/store/data/model/Accent.kt
Normal file
36
app/src/main/java/com/aurora/store/data/model/Accent.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
data class Accent(
|
||||
var id: Int,
|
||||
var accent: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is Accent -> other.id == id
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
40
app/src/main/java/com/aurora/store/data/model/Black.kt
Normal file
40
app/src/main/java/com/aurora/store/data/model/Black.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
data class Black(val packageName: String) {
|
||||
var displayName: String = String()
|
||||
var drawable: Drawable? = null
|
||||
var versionName: String = String()
|
||||
var versionCode: Int = 0
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return packageName.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is Black -> other.packageName == packageName
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
39
app/src/main/java/com/aurora/store/data/model/Dash.kt
Normal file
39
app/src/main/java/com/aurora/store/data/model/Dash.kt
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
data class Dash(
|
||||
var id: Int,
|
||||
var title: String,
|
||||
var subtitle: String,
|
||||
var icon: String,
|
||||
var url: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is Dash -> other.id == id
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
36
app/src/main/java/com/aurora/store/data/model/Download.kt
Normal file
36
app/src/main/java/com/aurora/store/data/model/Download.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
import com.tonyodev.fetch2.Download
|
||||
|
||||
data class DownloadFile(val download: Download) {
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return download.id
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is DownloadFile -> other.download.status == download.status && other.download.progress == download.progress
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
72
app/src/main/java/com/aurora/store/data/model/Exodus.kt
Normal file
72
app/src/main/java/com/aurora/store/data/model/Exodus.kt
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
import java.text.DateFormat
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class ExodusReport {
|
||||
val creator: String = String()
|
||||
val name: String = String()
|
||||
val reports: List<Report> = listOf()
|
||||
}
|
||||
|
||||
class Report {
|
||||
val id: Int = 0
|
||||
val downloads: String = String()
|
||||
val version: String = String()
|
||||
val creationDate: String = String()
|
||||
val updatedAt: String = String()
|
||||
val versionCode: String = String()
|
||||
val trackers: List<Int> = listOf()
|
||||
|
||||
fun getFormattedCreationDate(): String {
|
||||
return try {
|
||||
val simpleDateFormat: DateFormat = SimpleDateFormat(
|
||||
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
|
||||
Locale.getDefault()
|
||||
)
|
||||
simpleDateFormat.parse(creationDate).toString()
|
||||
} catch (e: ParseException) {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExodusTracker {
|
||||
var id: Int = 0
|
||||
var name: String = String()
|
||||
var url: String = String()
|
||||
var signature: String = String()
|
||||
var date: String = String()
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is ExodusTracker -> other.id == id
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
39
app/src/main/java/com/aurora/store/data/model/Installer.kt
Normal file
39
app/src/main/java/com/aurora/store/data/model/Installer.kt
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
data class Installer(
|
||||
var id: Int,
|
||||
var title: String,
|
||||
var subtitle: String,
|
||||
var description: String,
|
||||
var url: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is Installer -> other.id == id
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
39
app/src/main/java/com/aurora/store/data/model/Link.kt
Normal file
39
app/src/main/java/com/aurora/store/data/model/Link.kt
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
data class Link(
|
||||
var id: Int,
|
||||
var title: String,
|
||||
var subtitle: String,
|
||||
var url: String,
|
||||
var icon: Int,
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is Link -> other.id == id
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
37
app/src/main/java/com/aurora/store/data/model/Theme.kt
Normal file
37
app/src/main/java/com/aurora/store/data/model/Theme.kt
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
data class Theme(
|
||||
var id: Int,
|
||||
var title: String,
|
||||
var subtitle: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return when (other) {
|
||||
is Theme -> other.id == id
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
126
app/src/main/java/com/aurora/store/data/network/FuelClient.kt
Normal file
126
app/src/main/java/com/aurora/store/data/network/FuelClient.kt
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.network
|
||||
|
||||
import com.aurora.gplayapi.GooglePlayApi
|
||||
import com.aurora.gplayapi.data.models.PlayResponse
|
||||
import com.aurora.gplayapi.network.IHttpClient
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.util.Log
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import com.github.kittinunf.fuel.core.*
|
||||
import java.nio.charset.Charset
|
||||
|
||||
object FuelClient : IHttpClient {
|
||||
|
||||
override fun get(url: String, headers: Map<String, String>): PlayResponse {
|
||||
return get(url, headers, hashMapOf())
|
||||
}
|
||||
|
||||
override fun get(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
params: Map<String, String>
|
||||
): PlayResponse {
|
||||
val parameters = params
|
||||
.map { it.key to it.value }
|
||||
.toList()
|
||||
val (request, response, result) = Fuel.get(url, parameters)
|
||||
.header(headers)
|
||||
.response()
|
||||
return buildPlayResponse(response, request)
|
||||
}
|
||||
|
||||
override fun getAuth(url: String): PlayResponse {
|
||||
val (request, response, result) = Fuel.get(url)
|
||||
.appendHeader(
|
||||
"User-Agent",
|
||||
"${BuildConfig.APPLICATION_ID}-${BuildConfig.VERSION_NAME}-${BuildConfig.VERSION_CODE}"
|
||||
)
|
||||
.response()
|
||||
return buildPlayResponse(response, request)
|
||||
}
|
||||
|
||||
override fun get(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
paramString: String
|
||||
): PlayResponse {
|
||||
val (request, response, result) = Fuel.get(url + paramString)
|
||||
.header(headers)
|
||||
.response()
|
||||
return buildPlayResponse(response, request)
|
||||
}
|
||||
|
||||
override fun post(url: String, headers: Map<String, String>, body: ByteArray): PlayResponse {
|
||||
val (request, response, result) = Fuel.post(url)
|
||||
.header(headers)
|
||||
.appendHeader(Headers.CONTENT_TYPE, "application/x-protobuf")
|
||||
.body(body, Charset.defaultCharset())
|
||||
.response()
|
||||
return buildPlayResponse(response, request)
|
||||
}
|
||||
|
||||
override fun post(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
params: Map<String, String>
|
||||
): PlayResponse {
|
||||
val parameters = params
|
||||
.map { it.key to it.value }
|
||||
.toList()
|
||||
val (request, response, result) = Fuel.post(url, parameters)
|
||||
.header(headers)
|
||||
.response()
|
||||
return buildPlayResponse(response, request)
|
||||
}
|
||||
|
||||
override fun postAuth(url: String, body: ByteArray): PlayResponse {
|
||||
val (request, response, result) = Fuel.post(url)
|
||||
.appendHeader(
|
||||
"User-Agent",
|
||||
"${BuildConfig.APPLICATION_ID}-${BuildConfig.VERSION_NAME}-${BuildConfig.VERSION_CODE}"
|
||||
)
|
||||
.body(body)
|
||||
.response()
|
||||
return buildPlayResponse(response, request)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun buildPlayResponse(response: Response, request: Request): PlayResponse {
|
||||
return PlayResponse().apply {
|
||||
isSuccessful = response.isSuccessful
|
||||
code = response.statusCode
|
||||
|
||||
GooglePlayApi
|
||||
|
||||
if (response.isSuccessful) {
|
||||
responseBytes = response.body().toByteArray()
|
||||
}
|
||||
|
||||
if (response.isClientError || response.isServerError) {
|
||||
errorBytes = response.responseMessage.toByteArray()
|
||||
errorString = String(errorBytes)
|
||||
}
|
||||
}.also {
|
||||
Log.i("FUEL [${request.method}:${response.statusCode}] ${response.url}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.network
|
||||
|
||||
import android.os.Build
|
||||
import com.aurora.gplayapi.network.IHttpClient
|
||||
|
||||
object HttpClient {
|
||||
|
||||
fun getPreferredClient(): IHttpClient {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
OkHttpClient
|
||||
} else {
|
||||
FuelClient
|
||||
}
|
||||
}
|
||||
}
|
||||
169
app/src/main/java/com/aurora/store/data/network/OkHttpClient.kt
Normal file
169
app/src/main/java/com/aurora/store/data/network/OkHttpClient.kt
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.network
|
||||
|
||||
import com.aurora.gplayapi.data.models.PlayResponse
|
||||
import com.aurora.gplayapi.network.IHttpClient
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.util.Log
|
||||
import okhttp3.*
|
||||
import okhttp3.Headers.Companion.toHeaders
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object OkHttpClient : IHttpClient {
|
||||
|
||||
private const val POST = "POST"
|
||||
private const val GET = "GET"
|
||||
|
||||
private val okHttpClient = OkHttpClient().newBuilder()
|
||||
.connectTimeout(20, TimeUnit.SECONDS)
|
||||
.retryOnConnectionFailure(true)
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
.build()
|
||||
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun post(url: String, headers: Map<String, String>, requestBody: RequestBody): PlayResponse {
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.headers(headers.toHeaders())
|
||||
.method(POST, requestBody)
|
||||
.build()
|
||||
return processRequest(request)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun post(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
params: Map<String, String>
|
||||
): PlayResponse {
|
||||
val request = Request.Builder()
|
||||
.url(buildUrl(url, params))
|
||||
.headers(headers.toHeaders())
|
||||
.method(POST, "".toRequestBody(null))
|
||||
.build()
|
||||
return processRequest(request)
|
||||
}
|
||||
|
||||
override fun postAuth(url: String, body: ByteArray): PlayResponse {
|
||||
val requestBody = body.toRequestBody("application/json".toMediaType(), 0, body.size)
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.header(
|
||||
"User-Agent",
|
||||
"${BuildConfig.APPLICATION_ID}-${BuildConfig.VERSION_NAME}-${BuildConfig.VERSION_CODE}"
|
||||
)
|
||||
.method(POST, requestBody)
|
||||
.build()
|
||||
return processRequest(request)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun post(url: String, headers: Map<String, String>, body: ByteArray): PlayResponse {
|
||||
val requestBody = body.toRequestBody(
|
||||
"application/x-protobuf".toMediaType(),
|
||||
0,
|
||||
body.size
|
||||
)
|
||||
return post(url, headers, requestBody)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun get(url: String, headers: Map<String, String>): PlayResponse {
|
||||
return get(url, headers, mapOf())
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun get(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
params: Map<String, String>
|
||||
): PlayResponse {
|
||||
val request = Request.Builder()
|
||||
.url(buildUrl(url, params))
|
||||
.headers(headers.toHeaders())
|
||||
.method(GET, null)
|
||||
.build()
|
||||
return processRequest(request)
|
||||
}
|
||||
|
||||
override fun getAuth(url: String): PlayResponse {
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.header(
|
||||
"User-Agent",
|
||||
"${BuildConfig.APPLICATION_ID}-${BuildConfig.VERSION_NAME}-${BuildConfig.VERSION_CODE}"
|
||||
)
|
||||
.method(GET, null)
|
||||
.build()
|
||||
return processRequest(request)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun get(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
paramString: String
|
||||
): PlayResponse {
|
||||
val request = Request.Builder()
|
||||
.url(url + paramString)
|
||||
.headers(headers.toHeaders())
|
||||
.method(GET, null)
|
||||
.build()
|
||||
return processRequest(request)
|
||||
}
|
||||
|
||||
private fun processRequest(request: Request): PlayResponse {
|
||||
val call = okHttpClient.newCall(request)
|
||||
return buildPlayResponse(call.execute())
|
||||
}
|
||||
|
||||
private fun buildUrl(url: String, params: Map<String, String>): HttpUrl {
|
||||
val urlBuilder = url.toHttpUrl().newBuilder()
|
||||
params.forEach {
|
||||
urlBuilder.addQueryParameter(it.key, it.value)
|
||||
}
|
||||
return urlBuilder.build()
|
||||
}
|
||||
|
||||
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 {
|
||||
Log.i("OKHTTP [${response.code}] ${response.request.url}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.Constants
|
||||
import com.aurora.store.AccountType
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import com.aurora.store.util.Preferences
|
||||
|
||||
class AccountProvider private constructor(var context: Context) {
|
||||
|
||||
companion object : SingletonHolder<AccountProvider, Context>(::AccountProvider)
|
||||
|
||||
fun isSignedIn(): Boolean {
|
||||
return Preferences.getBoolean(context, Constants.ACCOUNT_SIGNED_IN)
|
||||
}
|
||||
|
||||
fun getSignInTimeStamp(): Long {
|
||||
return Preferences.getLong(context, Constants.ACCOUNT_SIGNED_TIMESTAMP)
|
||||
}
|
||||
|
||||
fun getAccountType(): AccountType {
|
||||
val rawType = Preferences.getString(context, Constants.ACCOUNT_TYPE)
|
||||
return when (rawType) {
|
||||
"GOOGLE" -> AccountType.GOOGLE
|
||||
else -> AccountType.ANONYMOUS
|
||||
}
|
||||
}
|
||||
|
||||
fun logout() {
|
||||
Preferences.putBoolean(context, Constants.ACCOUNT_SIGNED_IN, false)
|
||||
Preferences.putString(context, Constants.ACCOUNT_EMAIL_PLAIN, "")
|
||||
Preferences.putString(context, Constants.ACCOUNT_AAS_PLAIN, "")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import androidx.core.content.FileProvider
|
||||
|
||||
class ApkProvider : FileProvider() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.gplayapi.data.models.AuthData
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
class AuthProvider private constructor(var context: Context) {
|
||||
|
||||
companion object : SingletonHolder<AuthProvider, Context>(::AuthProvider)
|
||||
|
||||
private var gson: Gson = GsonBuilder()
|
||||
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
|
||||
.create()
|
||||
|
||||
fun getAuthData(): AuthData {
|
||||
return getSavedAuthData()
|
||||
}
|
||||
|
||||
private fun getSavedAuthData(): AuthData {
|
||||
Log.i("Loading saved AuthData")
|
||||
|
||||
val rawAuth: String = Preferences.getString(context, PREFERENCE_AUTH_DATA)
|
||||
return if (rawAuth.isNotEmpty())
|
||||
gson.fromJson(rawAuth, AuthData::class.java)
|
||||
else
|
||||
AuthData("", "")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
class BlacklistProvider private constructor(var context: Context) {
|
||||
|
||||
companion object : SingletonHolder<BlacklistProvider, Context>(::BlacklistProvider) {
|
||||
const val PREFERENCE_BLACKLIST = "PREFERENCE_BLACKLIST"
|
||||
}
|
||||
|
||||
private var gson: Gson = GsonBuilder()
|
||||
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
|
||||
.create()
|
||||
|
||||
fun getBlackList(): MutableSet<String> {
|
||||
val rawBlacklist = Preferences.getString(context, PREFERENCE_BLACKLIST)
|
||||
return try {
|
||||
if (rawBlacklist.isEmpty())
|
||||
mutableSetOf()
|
||||
else
|
||||
gson.fromJson(rawBlacklist, object : TypeToken<Set<String?>?>() {}.type)
|
||||
} catch (e: Exception) {
|
||||
mutableSetOf()
|
||||
}
|
||||
}
|
||||
|
||||
fun isBlacklisted(packageName: String): Boolean {
|
||||
return getBlackList().contains(packageName)
|
||||
}
|
||||
|
||||
fun blacklist(packageName: String) {
|
||||
val oldBlackList: MutableSet<String> = getBlackList()
|
||||
oldBlackList.add(packageName)
|
||||
save(oldBlackList)
|
||||
}
|
||||
|
||||
fun whitelist(packageName: String) {
|
||||
val oldBlackList: MutableSet<String> = getBlackList()
|
||||
oldBlackList.remove(packageName)
|
||||
save(oldBlackList)
|
||||
}
|
||||
|
||||
fun blacklist(packageNames: Set<String>) {
|
||||
val oldBlackList: MutableSet<String> = getBlackList()
|
||||
oldBlackList.addAll(packageNames)
|
||||
save(oldBlackList)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun save(blacklist: Set<String>) {
|
||||
Preferences.putString(context, PREFERENCE_BLACKLIST, gson.toJson(blacklist))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.opengl.GLES10
|
||||
import android.text.TextUtils
|
||||
import java.util.*
|
||||
import javax.microedition.khronos.egl.EGL10
|
||||
import javax.microedition.khronos.egl.EGLConfig
|
||||
import javax.microedition.khronos.egl.EGLContext
|
||||
import javax.microedition.khronos.egl.EGLDisplay
|
||||
|
||||
object EglExtensionProvider {
|
||||
@JvmStatic
|
||||
val eglExtensions: List<String>
|
||||
get() {
|
||||
val glExtensions: MutableSet<String> = HashSet()
|
||||
val egl10 = EGLContext.getEGL() as EGL10
|
||||
val display = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
|
||||
egl10.eglInitialize(display, IntArray(2))
|
||||
val cf = IntArray(1)
|
||||
if (egl10.eglGetConfigs(display, null, 0, cf)) {
|
||||
val configs = arrayOfNulls<EGLConfig>(cf[0])
|
||||
if (egl10.eglGetConfigs(display, configs, cf[0], cf)) {
|
||||
val a1 = intArrayOf(
|
||||
EGL10.EGL_WIDTH,
|
||||
EGL10.EGL_PBUFFER_BIT,
|
||||
EGL10.EGL_HEIGHT,
|
||||
EGL10.EGL_PBUFFER_BIT,
|
||||
EGL10.EGL_NONE
|
||||
)
|
||||
val a2 = intArrayOf(12440, EGL10.EGL_PIXMAP_BIT, EGL10.EGL_NONE)
|
||||
val a3 = IntArray(1)
|
||||
for (i in 0 until cf[0]) {
|
||||
egl10.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_CAVEAT, a3)
|
||||
if (a3[0] != EGL10.EGL_SLOW_CONFIG) {
|
||||
egl10.eglGetConfigAttrib(
|
||||
display,
|
||||
configs[i],
|
||||
EGL10.EGL_SURFACE_TYPE,
|
||||
a3
|
||||
)
|
||||
if (1 and a3[0] != 0) {
|
||||
egl10.eglGetConfigAttrib(
|
||||
display,
|
||||
configs[i],
|
||||
EGL10.EGL_RENDERABLE_TYPE,
|
||||
a3
|
||||
)
|
||||
if (1 and a3[0] != 0) {
|
||||
addExtensionsForConfig(
|
||||
egl10,
|
||||
display,
|
||||
configs[i],
|
||||
a1,
|
||||
null,
|
||||
glExtensions
|
||||
)
|
||||
}
|
||||
if (4 and a3[0] != 0) {
|
||||
addExtensionsForConfig(
|
||||
egl10,
|
||||
display,
|
||||
configs[i],
|
||||
a1,
|
||||
a2,
|
||||
glExtensions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
egl10.eglTerminate(display)
|
||||
val sorted: List<String> = ArrayList(glExtensions)
|
||||
Collections.sort(sorted)
|
||||
return sorted
|
||||
}
|
||||
|
||||
private fun addExtensionsForConfig(
|
||||
egl10: EGL10,
|
||||
eglDisplay: EGLDisplay,
|
||||
eglConfig: EGLConfig?,
|
||||
ai: IntArray,
|
||||
ai1: IntArray?,
|
||||
set: MutableSet<String>
|
||||
) {
|
||||
val eglContext = egl10.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, ai1)
|
||||
if (eglContext === EGL10.EGL_NO_CONTEXT) {
|
||||
return
|
||||
}
|
||||
val eglSurface = egl10.eglCreatePbufferSurface(eglDisplay, eglConfig, ai)
|
||||
if (eglSurface === EGL10.EGL_NO_SURFACE) {
|
||||
egl10.eglDestroyContext(eglDisplay, eglContext)
|
||||
} else {
|
||||
egl10.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)
|
||||
val s = GLES10.glGetString(7939)
|
||||
if (!TextUtils.isEmpty(s)) {
|
||||
val `as` = s.split(" ".toRegex()).toTypedArray()
|
||||
val i = `as`.size
|
||||
set.addAll(listOf(*`as`).subList(0, i))
|
||||
}
|
||||
egl10.eglMakeCurrent(
|
||||
eglDisplay,
|
||||
EGL10.EGL_NO_SURFACE,
|
||||
EGL10.EGL_NO_SURFACE,
|
||||
EGL10.EGL_NO_CONTEXT
|
||||
)
|
||||
egl10.eglDestroySurface(eglDisplay, eglSurface)
|
||||
egl10.eglDestroyContext(eglDisplay, eglContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
class ExodusDataProvider private constructor(val context: Context) {
|
||||
|
||||
companion object : SingletonHolder<ExodusDataProvider, Context>(::ExodusDataProvider)
|
||||
|
||||
private val exodusTrackers: JSONObject
|
||||
|
||||
init {
|
||||
exodusTrackers = loadLocalTrackers()
|
||||
}
|
||||
|
||||
fun getLocalTrackers(): JSONObject {
|
||||
return exodusTrackers
|
||||
}
|
||||
|
||||
fun getFilteredTrackers(trackerIds: List<Int>): List<JSONObject> {
|
||||
return trackerIds.map {
|
||||
exodusTrackers.getJSONObject(
|
||||
it.toString()
|
||||
)
|
||||
}.toList()
|
||||
}
|
||||
|
||||
private fun loadLocalTrackers(): JSONObject {
|
||||
val inputStream = context.assets.open("exodus_trackers.json")
|
||||
val bytes = ByteArray(inputStream.available())
|
||||
inputStream.read(bytes)
|
||||
inputStream.close()
|
||||
|
||||
val json = String(bytes, StandardCharsets.UTF_8)
|
||||
val jsonArray = JSONArray(json)
|
||||
return jsonArray.getJSONObject(0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import java.util.*
|
||||
|
||||
class NativeDeviceInfoProvider(context: Context) : ContextWrapper(context) {
|
||||
|
||||
fun getNativeDeviceProperties(): Properties {
|
||||
return Properties().apply {
|
||||
//Build Props
|
||||
setProperty("UserReadableName", Build.DEVICE)
|
||||
setProperty("Build.HARDWARE", Build.HARDWARE)
|
||||
setProperty(
|
||||
"Build.RADIO",
|
||||
if (Build.getRadioVersion() != null)
|
||||
Build.getRadioVersion()
|
||||
else
|
||||
"unknown"
|
||||
)
|
||||
setProperty("Build.FINGERPRINT", Build.FINGERPRINT)
|
||||
setProperty("Build.BRAND", Build.BRAND)
|
||||
setProperty("Build.DEVICE", Build.DEVICE)
|
||||
setProperty("Build.VERSION.SDK_INT", "${Build.VERSION.SDK_INT}")
|
||||
setProperty("Build.VERSION.RELEASE", Build.VERSION.RELEASE)
|
||||
setProperty("Build.MODEL", Build.MODEL)
|
||||
setProperty("Build.MANUFACTURER", Build.MANUFACTURER)
|
||||
setProperty("Build.PRODUCT", Build.PRODUCT)
|
||||
setProperty("Build.ID", Build.ID)
|
||||
setProperty("Build.BOOTLOADER", Build.BOOTLOADER)
|
||||
|
||||
val config = applicationContext.resources.configuration
|
||||
setProperty("TouchScreen", "${config.touchscreen}")
|
||||
setProperty("Keyboard", "${config.keyboard}")
|
||||
setProperty("Navigation", "${config.navigation}")
|
||||
setProperty("ScreenLayout", "${config.screenLayout and 15}")
|
||||
setProperty("HasHardKeyboard", "${config.keyboard == Configuration.KEYBOARD_QWERTY}")
|
||||
setProperty(
|
||||
"HasFiveWayNavigation",
|
||||
"${config.navigation == Configuration.NAVIGATIONHIDDEN_YES}"
|
||||
)
|
||||
|
||||
//Display Metrics
|
||||
val metrics = applicationContext.resources.displayMetrics
|
||||
setProperty("Screen.Density", "${metrics.densityDpi}")
|
||||
setProperty("Screen.Width", "${metrics.widthPixels}")
|
||||
setProperty("Screen.Height", "${metrics.heightPixels}")
|
||||
|
||||
|
||||
//Supported Platforms
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
setProperty("Platforms", Build.SUPPORTED_ABIS.joinToString(separator = ","))
|
||||
} else {
|
||||
val platform = mutableListOf<String>()
|
||||
if (!TextUtils.isEmpty(Build.CPU_ABI)) {
|
||||
platform.add(Build.CPU_ABI)
|
||||
}
|
||||
if (!TextUtils.isEmpty(Build.CPU_ABI2)) {
|
||||
platform.add(Build.CPU_ABI2)
|
||||
}
|
||||
|
||||
setProperty("Platforms", platform.joinToString(separator = ","))
|
||||
}
|
||||
//Supported Features
|
||||
setProperty("Features", getFeatures().joinToString(separator = ","))
|
||||
//Shared Locales
|
||||
setProperty("Locales", getLocales().joinToString(separator = ","))
|
||||
//Shared Libraries
|
||||
setProperty("SharedLibraries", getSharedLibraries().joinToString(separator = ","))
|
||||
//GL Extensions
|
||||
val activityManager =
|
||||
applicationContext.getSystemService(ACTIVITY_SERVICE) as ActivityManager
|
||||
setProperty(
|
||||
"GL.Version",
|
||||
activityManager.deviceConfigurationInfo.reqGlEsVersion.toString()
|
||||
)
|
||||
setProperty(
|
||||
"GL.Extensions",
|
||||
EglExtensionProvider.eglExtensions.joinToString(separator = ",")
|
||||
)
|
||||
|
||||
//Google Related Props
|
||||
val gsfVersionProvider = NativeGsfVersionProvider(applicationContext)
|
||||
setProperty("Client", "android-google")
|
||||
setProperty("GSF.version", "${gsfVersionProvider.getGsfVersionCode(true)}")
|
||||
setProperty("Vending.version", "${gsfVersionProvider.getVendingVersionCode(true)}")
|
||||
setProperty("Vending.versionString", gsfVersionProvider.getVendingVersionString(true))
|
||||
|
||||
//MISC
|
||||
setProperty("Roaming", "mobile-notroaming")
|
||||
setProperty("TimeZone", "UTC-10")
|
||||
|
||||
//Telephony (USA 3650 AT&T)
|
||||
setProperty("CellOperator", "310")
|
||||
setProperty("SimOperator", "38")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFeatures(): List<String> {
|
||||
val featureStringList: MutableList<String> = ArrayList()
|
||||
try {
|
||||
val availableFeatures = applicationContext.packageManager.systemAvailableFeatures
|
||||
for (feature in availableFeatures) {
|
||||
if (feature.name.isNotEmpty()) {
|
||||
featureStringList.add(feature.name)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
return featureStringList
|
||||
}
|
||||
|
||||
private fun getLocales(): List<String> {
|
||||
val localeList: MutableList<String> = ArrayList()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
localeList.addAll(listOf(*applicationContext.assets.locales))
|
||||
} else {
|
||||
for (locale in Locale.getAvailableLocales()) {
|
||||
localeList.add(locale.toString())
|
||||
}
|
||||
}
|
||||
val locales: MutableList<String> = ArrayList()
|
||||
for (locale in localeList) {
|
||||
if (TextUtils.isEmpty(locale)) {
|
||||
continue
|
||||
}
|
||||
locales.add(locale.replace("-", "_"))
|
||||
}
|
||||
return locales
|
||||
}
|
||||
|
||||
private fun getSharedLibraries(): List<String> {
|
||||
val systemSharedLibraryNames = applicationContext.packageManager.systemSharedLibraryNames
|
||||
val libraries: MutableList<String> = ArrayList()
|
||||
try {
|
||||
if (systemSharedLibraryNames != null) {
|
||||
libraries.addAll(listOf(*systemSharedLibraryNames))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
return libraries
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
|
||||
class NativeGsfVersionProvider(context: Context) {
|
||||
private var gsfVersionCode = 0
|
||||
private var vendingVersionCode = 0
|
||||
private var vendingVersionString = ""
|
||||
|
||||
init {
|
||||
try {
|
||||
gsfVersionCode =
|
||||
context.packageManager.getPackageInfo(GOOGLE_SERVICES_PACKAGE_ID, 0).versionCode
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
// com.google.android.gms not found
|
||||
}
|
||||
try {
|
||||
val packageInfo = context.packageManager.getPackageInfo(GOOGLE_VENDING_PACKAGE_ID, 0)
|
||||
vendingVersionCode = packageInfo.versionCode
|
||||
vendingVersionString = packageInfo.versionName
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
// com.android.vending not found
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
try {
|
||||
gsfVersionCode =
|
||||
context.packageManager.getPackageInfo(GOOGLE_SERVICES_PACKAGE_ID, 0).versionCode
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
// com.google.android.gms not found
|
||||
}
|
||||
try {
|
||||
val packageInfo = context.packageManager.getPackageInfo(GOOGLE_VENDING_PACKAGE_ID, 0)
|
||||
vendingVersionCode = packageInfo.versionCode
|
||||
vendingVersionString = packageInfo.versionName
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
// com.android.vending not found
|
||||
}
|
||||
}
|
||||
|
||||
fun getGsfVersionCode(defaultIfNotFound: Boolean): Int {
|
||||
return if (defaultIfNotFound && gsfVersionCode < GOOGLE_SERVICES_VERSION_CODE)
|
||||
GOOGLE_SERVICES_VERSION_CODE
|
||||
else
|
||||
gsfVersionCode
|
||||
}
|
||||
|
||||
fun getVendingVersionCode(defaultIfNotFound: Boolean): Int {
|
||||
return if (defaultIfNotFound && vendingVersionCode < GOOGLE_VENDING_VERSION_CODE)
|
||||
GOOGLE_VENDING_VERSION_CODE
|
||||
else
|
||||
vendingVersionCode
|
||||
}
|
||||
|
||||
fun getVendingVersionString(defaultIfNotFound: Boolean): String {
|
||||
return if (defaultIfNotFound && vendingVersionCode < GOOGLE_VENDING_VERSION_CODE)
|
||||
GOOGLE_VENDING_VERSION_STRING
|
||||
else
|
||||
vendingVersionString
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val GOOGLE_SERVICES_PACKAGE_ID = "com.google.android.gms"
|
||||
private const val GOOGLE_VENDING_PACKAGE_ID = "com.android.vending"
|
||||
private const val GOOGLE_SERVICES_VERSION_CODE = 203019037
|
||||
private const val GOOGLE_VENDING_VERSION_CODE = 82151710
|
||||
private const val GOOGLE_VENDING_VERSION_STRING = "21.5.17-21 [0] [PR] 326734551"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import com.aurora.store.util.Log
|
||||
import com.novoda.merlin.Merlin
|
||||
|
||||
class NetworkProvider(var context: Context) {
|
||||
|
||||
companion object : SingletonHolder<NetworkProvider, Context>(::NetworkProvider) {
|
||||
|
||||
private var networkListeners: MutableList<NetworkListener> = mutableListOf()
|
||||
|
||||
fun addListener(networkListener: NetworkListener) {
|
||||
Log.i("Network-Provider added to ${networkListener.javaClass.simpleName}")
|
||||
networkListeners.add(networkListener)
|
||||
}
|
||||
|
||||
fun removeListener(networkListener: NetworkListener) {
|
||||
Log.i("Network-Provider removed from ${networkListener.javaClass.simpleName}")
|
||||
networkListeners.remove(networkListener)
|
||||
}
|
||||
}
|
||||
|
||||
private var merlin: Merlin = Merlin.Builder()
|
||||
.withAllCallbacks()
|
||||
.build(context)
|
||||
|
||||
private var isDisconnected = true
|
||||
|
||||
fun bind() {
|
||||
merlin.bind()
|
||||
|
||||
merlin.registerConnectable {
|
||||
if (isDisconnected) {
|
||||
isDisconnected = false
|
||||
onReConnected()
|
||||
} else {
|
||||
onConnected()
|
||||
}
|
||||
}
|
||||
|
||||
merlin.registerDisconnectable {
|
||||
isDisconnected = true
|
||||
onDisconnected()
|
||||
}
|
||||
}
|
||||
|
||||
fun unbind() {
|
||||
networkListeners.clear()
|
||||
merlin.unbind()
|
||||
Log.i("Network-Provider destroyed")
|
||||
}
|
||||
|
||||
private fun onConnected() {
|
||||
Log.i("Network-Provider connected")
|
||||
isDisconnected = false
|
||||
networkListeners.forEach {
|
||||
it.onConnected()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onReConnected() {
|
||||
Log.i("Network-Provider reconnected")
|
||||
networkListeners.forEach {
|
||||
it.onReconnected()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDisconnected() {
|
||||
Log.e("Network-Provider disconnected")
|
||||
networkListeners.forEach {
|
||||
it.onDisconnected()
|
||||
}
|
||||
}
|
||||
|
||||
interface NetworkListener {
|
||||
fun onConnected()
|
||||
fun onDisconnected()
|
||||
fun onReconnected()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.PathUtil
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.jar.JarEntry
|
||||
import java.util.jar.JarFile
|
||||
|
||||
class SpoofDeviceProvider private constructor(var context: Context) {
|
||||
|
||||
companion object : SingletonHolder<SpoofDeviceProvider, Context>(::SpoofDeviceProvider) {
|
||||
private const val SUFFIX = ".properties"
|
||||
|
||||
fun filenameValid(filename: String): Boolean {
|
||||
return filename.endsWith(SUFFIX)
|
||||
}
|
||||
}
|
||||
|
||||
val availableDevice: List<Properties>
|
||||
get() {
|
||||
val propertiesList: MutableList<Properties> = ArrayList()
|
||||
propertiesList.add(0, NativeDeviceInfoProvider(context).getNativeDeviceProperties())
|
||||
propertiesList.addAll(spoofDevicesFromApk)
|
||||
propertiesList.addAll(spoofDevicesFromUser)
|
||||
return propertiesList
|
||||
}
|
||||
|
||||
private val spoofDevicesFromApk: List<Properties>
|
||||
get() {
|
||||
val jarFile = apkAsJar
|
||||
val propertiesList: MutableList<Properties> = ArrayList()
|
||||
if (null == jarFile) {
|
||||
return propertiesList
|
||||
}
|
||||
val entries = jarFile.entries()
|
||||
while (entries.hasMoreElements()) {
|
||||
val entry = entries.nextElement()
|
||||
if (!filenameValid(entry.name)) {
|
||||
continue
|
||||
}
|
||||
propertiesList.add(getProperties(jarFile, entry))
|
||||
}
|
||||
return propertiesList
|
||||
}
|
||||
|
||||
private val spoofDevicesFromUser: List<Properties>
|
||||
get() {
|
||||
val deviceNames: MutableList<Properties> = ArrayList()
|
||||
val defaultDir = File(PathUtil.getExternalPath())
|
||||
val files = defaultDir.listFiles()
|
||||
if (defaultDir.exists() && files != null) {
|
||||
for (file in files) {
|
||||
if (!file.isFile || !filenameValid(file.name)) {
|
||||
continue
|
||||
}
|
||||
deviceNames.add(getProperties(file))
|
||||
}
|
||||
}
|
||||
return deviceNames
|
||||
}
|
||||
|
||||
private fun getProperties(jarFile: JarFile, entry: JarEntry): Properties {
|
||||
val properties = Properties()
|
||||
try {
|
||||
properties.load(jarFile.getInputStream(entry))
|
||||
properties.setProperty("CONFIG_NAME", entry.name)
|
||||
} catch (e: IOException) {
|
||||
Log.e("Could not read %s", entry.name)
|
||||
}
|
||||
return properties
|
||||
}
|
||||
|
||||
private fun getProperties(file: File): Properties {
|
||||
val properties = Properties()
|
||||
try {
|
||||
properties.load(BufferedInputStream(FileInputStream(file)))
|
||||
properties.setProperty("CONFIG_NAME", file.name)
|
||||
} catch (e: IOException) {
|
||||
Log.e("Could not read %s", file.name)
|
||||
}
|
||||
return properties
|
||||
}
|
||||
|
||||
private val devicesFromApk: Map<String, String>
|
||||
get() {
|
||||
val deviceNames: MutableMap<String, String> = HashMap()
|
||||
val jarFile = apkAsJar ?: return deviceNames
|
||||
|
||||
val entries = jarFile.entries()
|
||||
while (entries.hasMoreElements()) {
|
||||
val entry = entries.nextElement()
|
||||
if (!filenameValid(entry.name)) {
|
||||
continue
|
||||
}
|
||||
|
||||
deviceNames[entry.name] =
|
||||
getProperties(jarFile, entry).getProperty("UserReadableName")
|
||||
}
|
||||
return deviceNames
|
||||
}
|
||||
|
||||
private val apkAsJar: JarFile?
|
||||
get() {
|
||||
val file = apkFile
|
||||
try {
|
||||
if (file != null && file.exists()) {
|
||||
return JarFile(file)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e("Could not open Aurora Store apk as a jar file")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private val apkFile: File?
|
||||
get() {
|
||||
try {
|
||||
val sourceDir: String = context.packageManager.getApplicationInfo(
|
||||
BuildConfig.APPLICATION_ID,
|
||||
0
|
||||
).sourceDir
|
||||
|
||||
if (sourceDir.isNotEmpty()) {
|
||||
return File(sourceDir)
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private val devicesFromDownloadDirectory: Map<String, String>
|
||||
get() {
|
||||
val deviceNames: MutableMap<String, String> = HashMap()
|
||||
val defaultDir = File(PathUtil.getExternalPath())
|
||||
if (!defaultDir.exists() || null == defaultDir.listFiles()) {
|
||||
return deviceNames
|
||||
}
|
||||
for (file in defaultDir.listFiles()) {
|
||||
if (!file.isFile || !filenameValid(file.name)) {
|
||||
continue
|
||||
}
|
||||
val name = getProperties(file).getProperty("UserReadableName")
|
||||
if (name != null) {
|
||||
deviceNames[file.name] = name
|
||||
}
|
||||
}
|
||||
return deviceNames
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.store.data.SingletonHolder
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.*
|
||||
|
||||
class SpoofProvider private constructor(var context: Context) {
|
||||
|
||||
companion object : SingletonHolder<SpoofProvider, Context>(::SpoofProvider) {
|
||||
const val LOCALE_SPOOF_ENABLED = "LOCALE_SPOOF_ENABLED"
|
||||
const val LOCALE_SPOOF_LANG = "LOCALE_SPOOF_LANG"
|
||||
const val LOCALE_SPOOF_COUNTRY = "LOCALE_SPOOF_COUNTRY"
|
||||
|
||||
const val DEVICE_SPOOF_ENABLED = "DEVICE_SPOOF_ENABLED"
|
||||
const val DEVICE_SPOOF_PROPERTIES = "DEVICE_SPOOF_PROPERTIES"
|
||||
}
|
||||
|
||||
fun isLocaleSpoofEnabled(): Boolean {
|
||||
return Preferences.getBoolean(context, LOCALE_SPOOF_ENABLED)
|
||||
}
|
||||
|
||||
fun isDeviceSpoofEnabled(): Boolean {
|
||||
return Preferences.getBoolean(context, DEVICE_SPOOF_ENABLED)
|
||||
}
|
||||
|
||||
fun getSpoofLocale(): Locale {
|
||||
return if (isLocaleSpoofEnabled()) {
|
||||
Locale(
|
||||
Preferences.getString(context, LOCALE_SPOOF_LANG),
|
||||
Preferences.getString(context, LOCALE_SPOOF_COUNTRY)
|
||||
)
|
||||
} else {
|
||||
Locale.getDefault()
|
||||
}
|
||||
}
|
||||
|
||||
fun getSpoofDeviceProperties(): Properties {
|
||||
return if (isDeviceSpoofEnabled()) {
|
||||
val gson: Gson =
|
||||
GsonBuilder().excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT)
|
||||
.create()
|
||||
return gson.fromJson(
|
||||
Preferences.getString(context, DEVICE_SPOOF_PROPERTIES),
|
||||
Properties::class.java
|
||||
)
|
||||
} else {
|
||||
Properties()
|
||||
}
|
||||
}
|
||||
|
||||
fun setSpoofLocale(locale: Locale) {
|
||||
Preferences.putBoolean(context, LOCALE_SPOOF_ENABLED, true)
|
||||
Preferences.putString(context, LOCALE_SPOOF_LANG, locale.language)
|
||||
Preferences.putString(context, LOCALE_SPOOF_COUNTRY, locale.country)
|
||||
}
|
||||
|
||||
fun setSpoofDeviceProperties(properties: Properties) {
|
||||
val gson: Gson =
|
||||
GsonBuilder().excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT)
|
||||
.create()
|
||||
Preferences.putBoolean(context, DEVICE_SPOOF_ENABLED, true)
|
||||
Preferences.putString(context, DEVICE_SPOOF_PROPERTIES, gson.toJson(properties))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.data.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
class BootReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.data.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.aurora.Constants.FETCH_GROUP_ID
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
|
||||
class DownloadCancelReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val extras = intent.extras
|
||||
if (extras != null) {
|
||||
val groupId = extras.getInt(FETCH_GROUP_ID, -1)
|
||||
DownloadManager
|
||||
.with(context)
|
||||
.getFetchInstance()
|
||||
.cancelGroup(groupId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.data.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.aurora.Constants.FETCH_GROUP_ID
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
|
||||
class DownloadPauseReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val extras = intent.extras
|
||||
if (extras != null) {
|
||||
val groupId: Int = extras.getInt(FETCH_GROUP_ID, -1)
|
||||
DownloadManager
|
||||
.with(context)
|
||||
.getFetchInstance()
|
||||
.pauseGroup(groupId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.data.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.aurora.Constants.FETCH_GROUP_ID
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
|
||||
class DownloadResumeReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val extras = intent.extras
|
||||
if (extras != null) {
|
||||
val groupId: Int = extras.getInt(FETCH_GROUP_ID, -1)
|
||||
DownloadManager
|
||||
.with(context)
|
||||
.getFetchInstance()
|
||||
.resumeGroup(groupId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.data.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
class InstallReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val extras = intent.extras
|
||||
if (extras != null) {
|
||||
/*val packageName = extras.getString(Constants.INTENT_PACKAGE_NAME, "")
|
||||
val versionString = extras.getString(Constants.DOWNLOAD_VERSION_CODE)
|
||||
if (!packageName.isEmpty() && versionString != null) {
|
||||
AuroraApplication.getInstaller().installSplit(packageName, versionString.toInt())
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.receiver
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.aurora.store.data.event.BusEvent.InstallEvent
|
||||
import com.aurora.store.data.event.BusEvent.UninstallEvent
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.util.PathUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.io.File
|
||||
|
||||
open class PackageManagerReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action != null && intent.data != null) {
|
||||
val packageName = intent.data!!.encodedSchemeSpecificPart
|
||||
|
||||
when (intent.action) {
|
||||
Intent.ACTION_PACKAGE_ADDED -> {
|
||||
EventBus.getDefault()
|
||||
.post(InstallEvent(packageName, ""))
|
||||
|
||||
//Clear installation queue
|
||||
AppInstaller.with(context)
|
||||
.getPreferredInstaller()
|
||||
.removeFromInstallQueue(packageName)
|
||||
}
|
||||
Intent.ACTION_PACKAGE_REMOVED -> EventBus.getDefault()
|
||||
.post(UninstallEvent(packageName, ""))
|
||||
}
|
||||
|
||||
clearNotification(context, packageName)
|
||||
|
||||
val isAutoDeleteAPKEnabled = Preferences.getBoolean(
|
||||
context,
|
||||
Preferences.PREFERENCE_AUTO_DELETE
|
||||
)
|
||||
|
||||
if (isAutoDeleteAPKEnabled)
|
||||
clearDownloads(context, packageName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearNotification(context: Context, packageName: String) {
|
||||
val notificationManager = context.applicationContext
|
||||
.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.cancel(packageName, packageName.hashCode())
|
||||
}
|
||||
|
||||
private fun clearDownloads(context: Context, packageName: String) {
|
||||
try {
|
||||
val rootDirPath = PathUtil.getPackageDirectory(context, packageName)
|
||||
val rootDir = File(rootDirPath)
|
||||
if (rootDir.exists())
|
||||
rootDir.deleteRecursively()
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
class UpdatesReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.service
|
||||
|
||||
import android.app.*
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.util.ArrayMap
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.aurora.Constants
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.receiver.DownloadCancelReceiver
|
||||
import com.aurora.store.data.receiver.DownloadPauseReceiver
|
||||
import com.aurora.store.data.receiver.DownloadResumeReceiver
|
||||
import com.aurora.store.data.receiver.InstallReceiver
|
||||
import com.aurora.store.util.CommonUtil
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.extensions.isLAndAbove
|
||||
import com.aurora.store.view.ui.details.AppDetailsActivity
|
||||
import com.aurora.store.view.ui.downloads.DownloadActivity
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.tonyodev.fetch2.*
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.*
|
||||
|
||||
class NotificationService : Service() {
|
||||
|
||||
companion object {
|
||||
fun startService(context: Context) {
|
||||
try {
|
||||
context.startService(Intent(context, NotificationService::class.java))
|
||||
} catch (e: Exception) {
|
||||
Log.e("Failed to start notification service : %s", e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var fetch: Fetch
|
||||
private lateinit var fetchListener: AbstractFetchGroupListener
|
||||
private lateinit var notificationManager: NotificationManager
|
||||
|
||||
private val appMap = ArrayMap<Int, App>()
|
||||
private val gson: Gson = GsonBuilder()
|
||||
.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT)
|
||||
.create()
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
Log.i("Notification Service Started")
|
||||
|
||||
notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
//Create Notification Channels : General & Alert
|
||||
createNotificationChannel()
|
||||
|
||||
fetch = DownloadManager.with(this).fetch
|
||||
|
||||
fetchListener = object : AbstractFetchGroupListener() {
|
||||
override fun onCancelled(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
showNotification(groupId, download, fetchGroup)
|
||||
}
|
||||
|
||||
override fun onCompleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
showNotification(groupId, download, fetchGroup)
|
||||
if (fetchGroup.groupDownloadProgress == 100) {
|
||||
install(download.tag!!, fetchGroup.downloads)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(
|
||||
groupId: Int,
|
||||
download: Download,
|
||||
error: Error,
|
||||
throwable: Throwable?,
|
||||
fetchGroup: FetchGroup
|
||||
) {
|
||||
showNotification(groupId, download, fetchGroup)
|
||||
}
|
||||
|
||||
override fun onProgress(
|
||||
groupId: Int,
|
||||
download: Download,
|
||||
etaInMilliSeconds: Long,
|
||||
downloadedBytesPerSecond: Long,
|
||||
fetchGroup: FetchGroup
|
||||
) {
|
||||
showNotification(groupId, download, fetchGroup)
|
||||
}
|
||||
|
||||
override fun onQueued(
|
||||
groupId: Int,
|
||||
download: Download,
|
||||
waitingNetwork: Boolean,
|
||||
fetchGroup: FetchGroup
|
||||
) {
|
||||
showNotification(groupId, download, fetchGroup)
|
||||
}
|
||||
|
||||
override fun onPaused(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
showNotification(groupId, download, fetchGroup)
|
||||
}
|
||||
}
|
||||
|
||||
fetch.addListener(fetchListener)
|
||||
}
|
||||
|
||||
private fun createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channels = ArrayList<NotificationChannel>()
|
||||
channels.add(
|
||||
NotificationChannel(
|
||||
Constants.NOTIFICATION_CHANNEL_ALERT,
|
||||
getString(R.string.notification_channel_alert),
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
)
|
||||
)
|
||||
channels.add(
|
||||
NotificationChannel(
|
||||
Constants.NOTIFICATION_CHANNEL_GENERAL,
|
||||
getString(R.string.notification_channel_general),
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
)
|
||||
)
|
||||
notificationManager.createNotificationChannels(channels)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showNotification(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
val status = download.status
|
||||
|
||||
//Ignore notifications for completion of sub-parts of a bundled apk
|
||||
if (status == Status.COMPLETED && fetchGroup.groupDownloadProgress < 100)
|
||||
return
|
||||
|
||||
//synchronized(appMap) {
|
||||
var app: App? = appMap[groupId]
|
||||
|
||||
if (app == null) {
|
||||
app = gson.fromJson(
|
||||
download.extras.getString(Constants.STRING_EXTRA, "{}"),
|
||||
App::class.java
|
||||
)
|
||||
appMap[groupId] = app
|
||||
}
|
||||
|
||||
if (app == null)
|
||||
return
|
||||
|
||||
val builder = NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNEL_GENERAL)
|
||||
builder.setContentTitle(app.displayName)
|
||||
builder.setSmallIcon(R.drawable.ic_notification_outlined)
|
||||
builder.color = ContextCompat.getColor(this, R.color.colorAccent)
|
||||
builder.setWhen(download.created)
|
||||
builder.setContentIntent(getContentIntentForDownloads())
|
||||
|
||||
when (status) {
|
||||
Status.PAUSED -> {
|
||||
builder.setSmallIcon(R.drawable.ic_download_pause)
|
||||
builder.setContentText(getString(R.string.download_paused))
|
||||
}
|
||||
Status.CANCELLED -> {
|
||||
builder.setSmallIcon(R.drawable.ic_download_cancel)
|
||||
builder.setContentText(getString(R.string.download_canceled))
|
||||
builder.color = Color.RED
|
||||
}
|
||||
Status.FAILED -> {
|
||||
builder.setSmallIcon(R.drawable.ic_download_fail)
|
||||
builder.setContentText(getString(R.string.download_failed))
|
||||
builder.color = Color.RED
|
||||
}
|
||||
Status.COMPLETED -> if (fetchGroup.groupDownloadProgress == 100) {
|
||||
builder.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
builder.setContentText(getString(R.string.download_completed))
|
||||
}
|
||||
else -> {
|
||||
builder.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
builder.setContentText(getString(R.string.download_metadata))
|
||||
}
|
||||
}
|
||||
val progress = fetchGroup.groupDownloadProgress
|
||||
val progressBigText = NotificationCompat.BigTextStyle()
|
||||
when (status) {
|
||||
|
||||
Status.QUEUED -> {
|
||||
builder.setProgress(100, 0, true)
|
||||
progressBigText.bigText(getString(R.string.download_queued))
|
||||
builder.setStyle(progressBigText)
|
||||
}
|
||||
|
||||
Status.DOWNLOADING -> {
|
||||
val contentString = getString(R.string.download_progress)
|
||||
val partString = StringUtils.joinWith(
|
||||
"/",
|
||||
fetchGroup.completedDownloads.size + 1,
|
||||
fetchGroup.downloads.size
|
||||
)
|
||||
val speedString: String =
|
||||
CommonUtil.humanReadableByteSpeed(download.downloadedBytesPerSecond, true)
|
||||
progressBigText.bigText(
|
||||
StringUtils.joinWith(
|
||||
" \u2022 ",
|
||||
contentString,
|
||||
partString,
|
||||
speedString
|
||||
)
|
||||
)
|
||||
builder.setStyle(progressBigText)
|
||||
builder.addAction(
|
||||
NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_download_pause,
|
||||
getString(R.string.action_pause),
|
||||
getPauseIntent(groupId)
|
||||
).build()
|
||||
)
|
||||
builder.addAction(
|
||||
NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_download_cancel,
|
||||
getString(R.string.action_cancel),
|
||||
getCancelIntent(groupId)
|
||||
).build()
|
||||
)
|
||||
if (progress < 0) builder.setProgress(
|
||||
100,
|
||||
0,
|
||||
true
|
||||
) else builder.setProgress(100, progress, false)
|
||||
}
|
||||
|
||||
Status.PAUSED -> {
|
||||
val pauseString = getString(R.string.download_paused)
|
||||
val filesString = StringUtils.joinWith(
|
||||
"/",
|
||||
fetchGroup.completedDownloads.size,
|
||||
fetchGroup.downloads.size
|
||||
)
|
||||
progressBigText.bigText(
|
||||
StringUtils.joinWith(
|
||||
" \u2022 ",
|
||||
pauseString,
|
||||
filesString
|
||||
)
|
||||
)
|
||||
builder.setStyle(progressBigText)
|
||||
builder.addAction(
|
||||
NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_download_pause,
|
||||
getString(R.string.action_resume),
|
||||
getResumeIntent(groupId)
|
||||
).build()
|
||||
)
|
||||
}
|
||||
|
||||
Status.COMPLETED -> if (fetchGroup.groupDownloadProgress == 100) {
|
||||
builder.setAutoCancel(true)
|
||||
builder.setContentIntent(getContentIntentForDetails(app))
|
||||
builder.setStyle(progressBigText)
|
||||
}
|
||||
else -> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (isLAndAbove()) {
|
||||
when (status) {
|
||||
Status.DOWNLOADING -> builder.setCategory(Notification.CATEGORY_PROGRESS)
|
||||
Status.FAILED, Status.CANCELLED -> builder.setCategory(Notification.CATEGORY_ERROR)
|
||||
else -> builder.setCategory(Notification.CATEGORY_STATUS)
|
||||
}
|
||||
}
|
||||
|
||||
notificationManager.notify(
|
||||
app.packageName,
|
||||
app.id,
|
||||
builder.build()
|
||||
)
|
||||
//}
|
||||
}
|
||||
|
||||
private fun getPauseIntent(groupId: Int): PendingIntent {
|
||||
val intent = Intent(this, DownloadPauseReceiver::class.java)
|
||||
intent.putExtra(Constants.FETCH_GROUP_ID, groupId)
|
||||
return PendingIntent.getBroadcast(this, groupId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
private fun getResumeIntent(groupId: Int): PendingIntent {
|
||||
val intent = Intent(this, DownloadResumeReceiver::class.java)
|
||||
intent.putExtra(Constants.FETCH_GROUP_ID, groupId)
|
||||
return PendingIntent.getBroadcast(this, groupId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
private fun getCancelIntent(groupId: Int): PendingIntent {
|
||||
val intent = Intent(this, DownloadCancelReceiver::class.java)
|
||||
intent.putExtra(Constants.FETCH_GROUP_ID, groupId)
|
||||
return PendingIntent.getBroadcast(this, groupId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
private fun getContentIntentForDetails(app: App?): PendingIntent {
|
||||
val intent = Intent(this, AppDetailsActivity::class.java)
|
||||
intent.putExtra(Constants.STRING_EXTRA, gson.toJson(app))
|
||||
return PendingIntent.getActivity(
|
||||
this,
|
||||
packageName.hashCode(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
}
|
||||
|
||||
private fun getContentIntentForDownloads(): PendingIntent {
|
||||
val intent = Intent(this, DownloadActivity::class.java)
|
||||
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
private fun getInstallIntent(packageName: String, versionCode: String): PendingIntent {
|
||||
val intent = Intent(this, InstallReceiver::class.java)
|
||||
intent.putExtra(Constants.STRING_EXTRA, packageName)
|
||||
return PendingIntent.getBroadcast(
|
||||
this,
|
||||
packageName.hashCode(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun install(packageName: String, files: List<Download>) {
|
||||
AppInstaller.with(this)
|
||||
.getPreferredInstaller()
|
||||
.install(
|
||||
packageName,
|
||||
files
|
||||
.filter { it.file.endsWith(".apk") }
|
||||
.map {
|
||||
it.file
|
||||
}.toList()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Log.i("Notification Service Stopped")
|
||||
fetch.removeListener(fetchListener)
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
66
app/src/main/java/com/aurora/store/util/AC2DMTask.kt
Normal file
66
app/src/main/java/com/aurora/store/util/AC2DMTask.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import java.util.*
|
||||
|
||||
class AC2DMTask {
|
||||
@Throws(Exception::class)
|
||||
fun getAC2DMResponse(email: String?, oAuthToken: String?): Map<String, String> {
|
||||
if (email == null || oAuthToken == null)
|
||||
return mapOf()
|
||||
|
||||
val params: MutableMap<String, Any> = hashMapOf()
|
||||
params["lang"] = Locale.getDefault().toString().replace("_", "-")
|
||||
params["google_play_services_version"] = PLAY_SERVICES_VERSION_CODE
|
||||
params["sdk_version"] = BUILD_VERSION_SDK
|
||||
params["device_country"] = Locale.getDefault().country.toLowerCase(Locale.US)
|
||||
params["Email"] = email
|
||||
params["service"] = "ac2dm"
|
||||
params["get_accountid"] = 1
|
||||
params["ACCESS_TOKEN"] = 1
|
||||
params["callerPkg"] = "com.google.android.gms"
|
||||
params["add_account"] = 1
|
||||
params["Token"] = oAuthToken
|
||||
params["callerSig"] = "38918a453d07199354f8b19af05ec6562ced5788"
|
||||
|
||||
val body = params.map { "${it.key}=${it.value}" }.joinToString(separator = "&")
|
||||
|
||||
val response = Fuel.post(TOKEN_AUTH_URL)
|
||||
.body(body)
|
||||
.header("app" to "com.google.android.gms")
|
||||
.header("User-Agent" to "")
|
||||
.header("Content-Type" to "application/x-www-form-urlencoded")
|
||||
.response()
|
||||
|
||||
return response.third.fold(success = {
|
||||
Util.parseResponse(String(it))
|
||||
}, failure = {
|
||||
mapOf()
|
||||
})
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TOKEN_AUTH_URL = "https://android.clients.google.com/auth"
|
||||
private const val BUILD_VERSION_SDK = 28
|
||||
private const val PLAY_SERVICES_VERSION_CODE = 19629032
|
||||
}
|
||||
}
|
||||
122
app/src/main/java/com/aurora/store/util/ApkCopier.kt
Normal file
122
app/src/main/java/com/aurora/store/util/ApkCopier.kt
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.FileProvider
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.util.extensions.isLAndAbove
|
||||
import org.apache.commons.io.IOUtils
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.*
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
class ApkCopier(private val context: Context, private val packageName: String) {
|
||||
|
||||
fun copy() {
|
||||
val destination = File(PathUtil.getBaseCopyDirectory())
|
||||
|
||||
destination.let {
|
||||
if (it.exists()) {
|
||||
Log.i("Base copy directory is available")
|
||||
} else {
|
||||
it.mkdirs()
|
||||
Log.e("Base copy directory is created : ${it.path}")
|
||||
}
|
||||
}
|
||||
|
||||
val packageInfo: PackageInfo = context.packageManager.getPackageInfo(
|
||||
packageName,
|
||||
PackageManager.GET_META_DATA
|
||||
)
|
||||
|
||||
val baseApk = getBaseApk(packageInfo)
|
||||
val fileList: MutableList<File?> = mutableListOf()
|
||||
|
||||
/*Add base APK*/
|
||||
fileList.add(baseApk)
|
||||
|
||||
if (isLAndAbove()) {
|
||||
val splitSourceDirs = packageInfo.applicationInfo.splitSourceDirs
|
||||
if (splitSourceDirs != null && splitSourceDirs.isNotEmpty()) {
|
||||
/*Add Split APKs*/
|
||||
fileList.addAll(getSplitAPKs(packageInfo))
|
||||
}
|
||||
bundleAllAPKs(fileList)
|
||||
} else {
|
||||
bundleAllAPKs(fileList)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBaseApk(packageInfo: PackageInfo?): File? {
|
||||
return if (packageInfo?.applicationInfo != null) {
|
||||
File(packageInfo.applicationInfo.sourceDir)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private fun getSplitAPKs(packageInfo: PackageInfo): MutableList<File> {
|
||||
val fileList: MutableList<File> = ArrayList()
|
||||
val splitSourceDirs = packageInfo.applicationInfo.splitSourceDirs
|
||||
if (splitSourceDirs != null) {
|
||||
for (fileName in splitSourceDirs) fileList.add(File(fileName))
|
||||
}
|
||||
return fileList
|
||||
}
|
||||
|
||||
private fun bundleAllAPKs(fileList: List<File?>) {
|
||||
try {
|
||||
val fileOutputStream =
|
||||
FileOutputStream(PathUtil.getBaseCopyDirectory() + "$packageName.zip")
|
||||
val zipOutputStream = ZipOutputStream(fileOutputStream)
|
||||
|
||||
for (file in fileList) {
|
||||
file?.let {
|
||||
val zipEntry = ZipEntry(file.name)
|
||||
zipOutputStream.putNextEntry(zipEntry)
|
||||
IOUtils.copy(it.inputStream(), zipOutputStream)
|
||||
zipOutputStream.closeEntry()
|
||||
}
|
||||
}
|
||||
|
||||
zipOutputStream.close()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Log.e("ApkCopier : %s", e.message)
|
||||
}
|
||||
}
|
||||
|
||||
fun getUri(file: File): Uri {
|
||||
return FileProvider.getUriForFile(
|
||||
context,
|
||||
"${BuildConfig.APPLICATION_ID}.fileProvider",
|
||||
file
|
||||
)
|
||||
}
|
||||
}
|
||||
100
app/src/main/java/com/aurora/store/util/CertUtil.kt
Normal file
100
app/src/main/java/com/aurora/store/util/CertUtil.kt
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import com.aurora.store.util.extensions.isPAndAbove
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
|
||||
object CertUtil {
|
||||
private const val FDROID = "FDROID"
|
||||
private const val GUARDIAN = "GUARDIANPROJECT.INFO"
|
||||
|
||||
private fun getX509Certificates(
|
||||
context: Context,
|
||||
packageName: String
|
||||
): List<X509Certificate?> {
|
||||
val certificates: MutableList<X509Certificate?> = mutableListOf()
|
||||
val packageManager = context.applicationContext.packageManager
|
||||
|
||||
try {
|
||||
|
||||
val packageInfo = if (isPAndAbove())
|
||||
packageManager.getPackageInfo(
|
||||
packageName,
|
||||
PackageManager.GET_SIGNING_CERTIFICATES
|
||||
)
|
||||
else
|
||||
packageManager.getPackageInfo(
|
||||
packageName,
|
||||
PackageManager.GET_SIGNATURES
|
||||
)
|
||||
|
||||
val certificateFactory = CertificateFactory.getInstance("X509")
|
||||
|
||||
if (isPAndAbove()) {
|
||||
packageInfo.signingInfo.apkContentsSigners.forEach {
|
||||
val bytes = it.toByteArray()
|
||||
val inputStream: InputStream = ByteArrayInputStream(bytes)
|
||||
certificates.add(
|
||||
certificateFactory!!.generateCertificate(inputStream) as X509Certificate
|
||||
)
|
||||
}
|
||||
} else {
|
||||
for (i in 0..packageInfo.signatures.size) {
|
||||
val bytes = packageInfo.signatures[i].toByteArray()
|
||||
val inStream: InputStream = ByteArrayInputStream(bytes)
|
||||
certificates.add(
|
||||
certificateFactory!!.generateCertificate(inStream) as X509Certificate
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(e.message)
|
||||
}
|
||||
|
||||
return certificates
|
||||
}
|
||||
|
||||
fun isFDroidApp(context: Context, packageName: String): Boolean {
|
||||
val certificates = getX509Certificates(context, packageName)
|
||||
|
||||
return if (certificates.isEmpty())
|
||||
false
|
||||
else {
|
||||
val cert = certificates[0]
|
||||
if (cert != null) {
|
||||
if (cert.subjectDN != null) {
|
||||
val DN = cert.subjectDN.name.toUpperCase(Locale.getDefault())
|
||||
DN.contains(FDROID) || DN.contains(GUARDIAN)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
189
app/src/main/java/com/aurora/store/util/CommonUtil.kt
Normal file
189
app/src/main/java/com/aurora/store/util/CommonUtil.kt
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
import com.aurora.store.R
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.pow
|
||||
|
||||
object CommonUtil {
|
||||
|
||||
private val siPrefixes: Map<Int, String> = hashMapOf(
|
||||
Pair(1, ""),
|
||||
Pair(3, " KB"),
|
||||
Pair(6, " MB"),
|
||||
Pair(9, " GB")
|
||||
)
|
||||
private val diPrefixes: Map<Int, String> = hashMapOf(
|
||||
Pair(1, ""),
|
||||
Pair(3, " K"),
|
||||
Pair(6, " Million"),
|
||||
Pair(9, " Billion")
|
||||
)
|
||||
|
||||
fun addSiPrefix(value: Long): String {
|
||||
if (value <= 0L)
|
||||
return "NA"
|
||||
var tempValue = value
|
||||
var order = 0
|
||||
while (tempValue >= 1000.0) {
|
||||
tempValue /= 1000.toLong()
|
||||
order += 3
|
||||
}
|
||||
return tempValue.toString() + siPrefixes[order]
|
||||
}
|
||||
|
||||
fun addDiPrefix(value: Long): String {
|
||||
if (value <= 0L)
|
||||
return "NA"
|
||||
var tempValue = value
|
||||
var order = 0
|
||||
while (tempValue >= 1000.0) {
|
||||
tempValue /= 1000.0.toLong()
|
||||
order += 3
|
||||
}
|
||||
return tempValue.toString() + diPrefixes[order]
|
||||
}
|
||||
|
||||
fun getETAString(context: Context, etaInMilliSeconds: Long): String {
|
||||
if (etaInMilliSeconds < 0) {
|
||||
return context.getString(R.string.download_eta_calculating)
|
||||
}
|
||||
var seconds = (etaInMilliSeconds / 1000).toInt()
|
||||
val hours = (seconds / 3600).toLong()
|
||||
seconds -= (hours * 3600).toInt()
|
||||
val minutes = (seconds / 60).toLong()
|
||||
seconds -= (minutes * 60).toInt()
|
||||
return when {
|
||||
hours > 0 -> {
|
||||
context.getString(R.string.download_eta_hrs, hours, minutes, seconds)
|
||||
}
|
||||
minutes > 0 -> {
|
||||
context.getString(R.string.download_eta_min, minutes, seconds)
|
||||
}
|
||||
else -> {
|
||||
context.getString(R.string.download_eta_sec, seconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun humanReadableByteSpeed(bytes: Long, si: Boolean): String {
|
||||
val unit = if (si) 1000 else 1024
|
||||
if (bytes < unit) return "$bytes B"
|
||||
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
||||
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1].toString() + if (si) "" else "i"
|
||||
return String.format(
|
||||
Locale.getDefault(), "%.1f %sB/s",
|
||||
bytes / unit.toDouble().pow(exp.toDouble()),
|
||||
pre
|
||||
)
|
||||
}
|
||||
|
||||
fun humanReadableByteValue(bytes: Long, si: Boolean): String {
|
||||
val unit = if (si) 1000 else 1024
|
||||
if (bytes < unit) return "$bytes B"
|
||||
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
||||
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1].toString() + if (si) "" else "i"
|
||||
return String.format(
|
||||
Locale.getDefault(), "%.1f %sB",
|
||||
bytes / unit.toDouble().pow(exp.toDouble()),
|
||||
pre
|
||||
)
|
||||
}
|
||||
|
||||
fun getDownloadSpeedString(context: Context, downloadedBytesPerSecond: Long): String {
|
||||
if (downloadedBytesPerSecond < 0) {
|
||||
return context.getString(R.string.download_speed_estimating)
|
||||
}
|
||||
val kb = downloadedBytesPerSecond.toDouble() / 1000.toDouble()
|
||||
val mb = kb / 1000.toDouble()
|
||||
val decimalFormat = DecimalFormat(".##")
|
||||
return when {
|
||||
mb >= 1 -> {
|
||||
context.getString(R.string.download_speed_mb, decimalFormat.format(mb))
|
||||
}
|
||||
kb >= 1 -> {
|
||||
context.getString(R.string.download_speed_kb, decimalFormat.format(kb))
|
||||
}
|
||||
else -> {
|
||||
context.getString(R.string.download_speed_bytes, downloadedBytesPerSecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getEmptyActivityBundle(context: Context): Bundle? {
|
||||
return ActivityOptionsCompat.makeCustomAnimation(
|
||||
context,
|
||||
android.R.anim.fade_in,
|
||||
android.R.anim.fade_out
|
||||
).toBundle()
|
||||
}
|
||||
|
||||
fun cleanupInstallationSessions(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val packageInstaller = context.packageManager.packageInstaller
|
||||
for (sessionInfo in packageInstaller.mySessions) {
|
||||
try {
|
||||
val sessionId = sessionInfo.sessionId
|
||||
packageInstaller.abandonSession(sessionInfo.sessionId)
|
||||
Log.i("Abandoned session id -> %d", sessionId)
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getThemeStyleById(themeId: Int): Int {
|
||||
return when (themeId) {
|
||||
0 -> R.style.AppTheme
|
||||
1 -> R.style.AppTheme_Light
|
||||
2 -> R.style.AppTheme_Dark
|
||||
3 -> R.style.AppTheme_Black
|
||||
4 -> R.style.AppTheme_DarkX
|
||||
5 -> R.style.AppTheme_Darkord
|
||||
else -> R.style.AppTheme
|
||||
}
|
||||
}
|
||||
|
||||
fun getAccentStyleById(accentId: Int): Int {
|
||||
return when (accentId) {
|
||||
1 -> R.style.Accent01
|
||||
2 -> R.style.Accent02
|
||||
3 -> R.style.Accent03
|
||||
4 -> R.style.Accent04
|
||||
5 -> R.style.Accent05
|
||||
6 -> R.style.Accent06
|
||||
7 -> R.style.Accent07
|
||||
8 -> R.style.Accent08
|
||||
9 -> R.style.Accent09
|
||||
10 -> R.style.Accent10
|
||||
11 -> R.style.Accent11
|
||||
12 -> R.style.Accent12
|
||||
else -> R.style.Accent01
|
||||
}
|
||||
}
|
||||
}
|
||||
73
app/src/main/java/com/aurora/store/util/Log.kt
Normal file
73
app/src/main/java/com/aurora/store/util/Log.kt
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.io.IOException
|
||||
|
||||
object Log {
|
||||
|
||||
const val TAG = "¯\\_(ツ)_/¯ "
|
||||
|
||||
fun e(message: String?, vararg args: Any?) {
|
||||
e(String.format(message!!, *args))
|
||||
}
|
||||
|
||||
fun e(message: String?) {
|
||||
Log.e(TAG, message!!)
|
||||
}
|
||||
|
||||
fun i(message: String?, vararg args: Any?) {
|
||||
i(String.format(message!!, *args))
|
||||
}
|
||||
|
||||
fun i(message: String?) {
|
||||
Log.i(TAG, message!!)
|
||||
}
|
||||
|
||||
fun d(message: String?, vararg args: Any?) {
|
||||
d(String.format(message!!, *args))
|
||||
}
|
||||
|
||||
fun d(message: String?) {
|
||||
Log.d(TAG, message!!)
|
||||
}
|
||||
|
||||
fun w(message: String?, vararg args: Any?) {
|
||||
w(String.format(message!!, *args))
|
||||
}
|
||||
|
||||
fun w(message: String?) {
|
||||
Log.w(TAG, message!!)
|
||||
}
|
||||
|
||||
fun writeToFile(context: Context, obj: Any) {
|
||||
try {
|
||||
val out = FileWriter(File(context.filesDir, "AuroraLogs.txt"))
|
||||
out.write(obj.toString())
|
||||
out.close()
|
||||
} catch (e: IOException) {
|
||||
e(e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
99
app/src/main/java/com/aurora/store/util/NavigationUtil.kt
Normal file
99
app/src/main/java/com/aurora/store/util/NavigationUtil.kt
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.app.ActivityOptions
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.aurora.Constants
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.store.data.model.Report
|
||||
import com.aurora.store.view.ui.details.AppDetailsActivity
|
||||
import com.aurora.store.view.ui.details.DetailsExodusActivity
|
||||
import com.aurora.store.view.ui.details.DevAppsActivity
|
||||
import com.aurora.store.view.ui.search.SearchResultsActivity
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
object NavigationUtil {
|
||||
val gson: Gson = GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).create()
|
||||
|
||||
fun openDetailsActivity(context: Context, app: App) {
|
||||
val intent = Intent(
|
||||
context,
|
||||
AppDetailsActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.STRING_EXTRA, gson.toJson(app))
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val options = ActivityOptions.makeSceneTransitionAnimation(context as AppCompatActivity)
|
||||
context.startActivity(intent, options.toBundle())
|
||||
} else {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
fun openDevAppsActivity(context: Context, app: App) {
|
||||
val intent = Intent(
|
||||
context,
|
||||
DevAppsActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.STRING_APP, gson.toJson(app))
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val options = ActivityOptions.makeSceneTransitionAnimation(context as AppCompatActivity)
|
||||
context.startActivity(intent, options.toBundle())
|
||||
} else {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
fun openExodusActivity(context: Context, app: App, report: Report) {
|
||||
val intent = Intent(
|
||||
context,
|
||||
DetailsExodusActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.STRING_APP, gson.toJson(app))
|
||||
putExtra(Constants.STRING_EXTRA, gson.toJson(report))
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val options = ActivityOptions.makeSceneTransitionAnimation(context as AppCompatActivity)
|
||||
context.startActivity(intent, options.toBundle())
|
||||
} else {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
fun openSearchActivity(context: Context) {
|
||||
val intent = Intent(
|
||||
context,
|
||||
SearchResultsActivity::class.java
|
||||
)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val options = ActivityOptions.makeSceneTransitionAnimation(context as AppCompatActivity)
|
||||
context.startActivity(intent, options.toBundle())
|
||||
} else {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
155
app/src/main/java/com/aurora/store/util/PackageUtil.kt
Normal file
155
app/src/main/java/com/aurora/store/util/PackageUtil.kt
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
|
||||
|
||||
object PackageUtil {
|
||||
|
||||
fun isInstalled(context: Context, packageName: String): Boolean {
|
||||
return try {
|
||||
context.packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA)
|
||||
true
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isUpdatable(context: Context, packageName: String, versionCode: Long): Boolean {
|
||||
return try {
|
||||
val packageInfo = getPackageInfo(context, packageName)
|
||||
if (packageInfo != null) {
|
||||
return versionCode > packageInfo.versionCode
|
||||
}
|
||||
true
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isTv(context: Context): Boolean {
|
||||
val uiMode = context.resources.configuration.uiMode
|
||||
return uiMode and Configuration.UI_MODE_TYPE_MASK == Configuration.UI_MODE_TYPE_TELEVISION
|
||||
}
|
||||
|
||||
fun getLaunchIntent(context: Context, packageName: String?): Intent? {
|
||||
val isTv = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && isTv(context)
|
||||
val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (isTv) {
|
||||
context.packageManager.getLeanbackLaunchIntentForPackage(packageName!!)
|
||||
} else {
|
||||
context.packageManager.getLaunchIntentForPackage(packageName!!)
|
||||
}
|
||||
} else {
|
||||
context.packageManager.getLaunchIntentForPackage(packageName!!)
|
||||
}
|
||||
|
||||
return if (intent == null) {
|
||||
null
|
||||
} else {
|
||||
intent.addCategory(if (isTv) Intent.CATEGORY_LEANBACK_LAUNCHER else Intent.CATEGORY_LAUNCHER)
|
||||
intent
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun getPackageInfo(context: Context, packageName: String?): PackageInfo? {
|
||||
return context.packageManager.getPackageInfo(packageName!!, 0)
|
||||
}
|
||||
|
||||
fun getAllPackages(context: Context): List<PackageInfo> {
|
||||
val packageInfoSet: MutableList<PackageInfo> = mutableListOf()
|
||||
val packageManager: PackageManager = context.packageManager
|
||||
val flags: Int = getAllFlags()
|
||||
val packageInfoList: List<PackageInfo> = packageManager.getInstalledPackages(flags)
|
||||
for (packageInfo in packageInfoList) {
|
||||
if (packageInfo.packageName != null && packageInfo.applicationInfo != null) {
|
||||
packageInfoSet.add(packageInfo)
|
||||
}
|
||||
}
|
||||
return packageInfoSet
|
||||
}
|
||||
|
||||
fun getPackageInfoMap(context: Context): MutableMap<String, PackageInfo> {
|
||||
val packageInfoSet: MutableMap<String, PackageInfo> = mutableMapOf()
|
||||
val packageManager: PackageManager = context.packageManager
|
||||
val flags: Int = PackageManager.GET_META_DATA
|
||||
var packageInfoList: List<PackageInfo> = packageManager.getInstalledPackages(flags)
|
||||
|
||||
val isFdroidFilterEnabled = Preferences.getBoolean(
|
||||
context,
|
||||
Preferences.PREFERENCE_FILTER_FDROID
|
||||
)
|
||||
|
||||
packageInfoList = packageInfoList
|
||||
.filter {
|
||||
it.packageName != null && it.applicationInfo != null && it.applicationInfo.enabled
|
||||
}
|
||||
|
||||
if (isFdroidFilterEnabled) {
|
||||
packageInfoList
|
||||
.filter {
|
||||
val packageInstaller = packageManager.getInstallerPackageName(it.packageName)
|
||||
packageInstaller != "org.fdroid.fdroid.privileged"
|
||||
}.filter {
|
||||
!CertUtil.isFDroidApp(context, it.packageName)
|
||||
}
|
||||
}
|
||||
|
||||
packageInfoList.forEach {
|
||||
packageInfoSet[it.packageName] = it
|
||||
}
|
||||
|
||||
return packageInfoSet
|
||||
}
|
||||
|
||||
|
||||
fun getFilter(): IntentFilter {
|
||||
val filter = IntentFilter()
|
||||
filter.addDataScheme("package")
|
||||
filter.addAction(Intent.ACTION_PACKAGE_INSTALL)
|
||||
filter.addAction(Intent.ACTION_PACKAGE_ADDED)
|
||||
filter.addAction(Intent.ACTION_PACKAGE_REMOVED)
|
||||
return filter
|
||||
}
|
||||
|
||||
private fun getAllFlags(): Int {
|
||||
var flags = (PackageManager.GET_META_DATA
|
||||
or PackageManager.GET_ACTIVITIES
|
||||
or PackageManager.GET_SERVICES
|
||||
or PackageManager.GET_PROVIDERS
|
||||
or PackageManager.GET_RECEIVERS)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
flags = flags or PackageManager.GET_DISABLED_COMPONENTS
|
||||
flags = flags or PackageManager.GET_UNINSTALLED_PACKAGES
|
||||
} else {
|
||||
flags = flags or PackageManager.MATCH_DISABLED_COMPONENTS
|
||||
flags = flags or PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||
}
|
||||
return flags
|
||||
}
|
||||
}
|
||||
78
app/src/main/java/com/aurora/store/util/PathUtil.kt
Normal file
78
app/src/main/java/com/aurora/store/util/PathUtil.kt
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
import com.aurora.store.util.extensions.isLAndAbove
|
||||
|
||||
fun Context.getInternalBaseDirectory(): String {
|
||||
return filesDir.path
|
||||
}
|
||||
|
||||
object PathUtil {
|
||||
|
||||
private fun getDownloadDirectory(context: Context): String {
|
||||
return if (isLAndAbove())
|
||||
context.getInternalBaseDirectory() + "/Downloads"
|
||||
else
|
||||
getExternalPath()
|
||||
}
|
||||
|
||||
fun getPackageDirectory(context: Context, packageName: String): String {
|
||||
return getDownloadDirectory(context) + "/$packageName"
|
||||
}
|
||||
|
||||
private fun getVersionDirectory(
|
||||
context: Context,
|
||||
packageName: String,
|
||||
versionCode: Int
|
||||
): String {
|
||||
return getPackageDirectory(context, packageName) + "/$versionCode"
|
||||
}
|
||||
|
||||
fun getApkDownloadFile(context: Context, app: App, file: File): String {
|
||||
return getVersionDirectory(context, app.packageName, app.versionCode) + "/${file.name}"
|
||||
}
|
||||
|
||||
fun getApkDownloadFile(context: Context, packageName: String, versionCode: Int): String {
|
||||
return getVersionDirectory(context, packageName, versionCode)
|
||||
}
|
||||
|
||||
fun getExternalPath(): String {
|
||||
return Environment.getExternalStorageDirectory().toString() + "/Aurora/"
|
||||
}
|
||||
|
||||
fun getBaseCopyDirectory(): String {
|
||||
return "${getExternalPath()}/files/export/"
|
||||
}
|
||||
|
||||
private fun getObbDownloadPath(context: Context, app: App): String {
|
||||
return Environment.getExternalStorageDirectory()
|
||||
.toString() + "/Android/obb/" + app.packageName
|
||||
}
|
||||
|
||||
fun getObbDownloadFile(context: Context, app: App, file: File): String {
|
||||
val obbDir = getObbDownloadPath(context, app)
|
||||
return "$obbDir/${file.name}"
|
||||
}
|
||||
}
|
||||
114
app/src/main/java/com/aurora/store/util/Preferences.kt
Normal file
114
app/src/main/java/com/aurora/store/util/Preferences.kt
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.preference.PreferenceManager
|
||||
|
||||
object Preferences {
|
||||
|
||||
const val PREFERENCE_AUTH_DATA = "PREFERENCE_AUTH_DATA"
|
||||
const val PREFERENCE_INSTALLER_ID = "PREFERENCE_INSTALLER_ID"
|
||||
const val PREFERENCE_THEME_TYPE = "PREFERENCE_THEME_TYPE"
|
||||
const val PREFERENCE_THEME_ACCENT = "PREFERENCE_THEME_ACCENT"
|
||||
const val PREFERENCE_INTRO = "PREFERENCE_INTRO"
|
||||
|
||||
const val PREFERENCE_FILTER_GOOGLE = "PREFERENCE_FILTER_GOOGLE"
|
||||
const val PREFERENCE_FILTER_FDROID = "PREFERENCE_FILTER_FDROID"
|
||||
|
||||
const val PREFERENCE_AUTO_INSTALL = "PREFERENCE_AUTO_INSTALL"
|
||||
const val PREFERENCE_AUTO_DELETE = "PREFERENCE_AUTO_DELETE"
|
||||
|
||||
const val INSTALLATION_ABANDON_SESSION = "INSTALLATION_ABANDON_SESSION"
|
||||
|
||||
const val PREFERENCE_DOWNLOAD_ACTIVE = "PREFERENCE_DOWNLOAD_ACTIVE"
|
||||
const val PREFERENCE_DOWNLOAD_WIFI = "PREFERENCE_DOWNLOAD_WIFI"
|
||||
|
||||
|
||||
private fun getPrefs(context: Context): SharedPreferences {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context)
|
||||
}
|
||||
|
||||
fun putString(context: Context, key: String, value: String) {
|
||||
getPrefs(context).edit().putString(key, value).apply()
|
||||
}
|
||||
|
||||
fun putInteger(context: Context, key: String, value: Int) {
|
||||
getPrefs(context).edit().putInt(key, value).apply()
|
||||
}
|
||||
|
||||
fun putFloat(context: Context, key: String, value: Float) {
|
||||
getPrefs(context).edit().putFloat(key, value).apply()
|
||||
}
|
||||
|
||||
fun putLong(context: Context, key: String, value: Long) {
|
||||
getPrefs(context).edit().putLong(key, value).apply()
|
||||
}
|
||||
|
||||
fun putBoolean(context: Context, key: String, value: Boolean) {
|
||||
getPrefs(context).edit().putBoolean(key, value).apply()
|
||||
}
|
||||
|
||||
fun getString(context: Context, key: String): String {
|
||||
return getPrefs(context).getString(key, "").toString()
|
||||
}
|
||||
|
||||
fun getInteger(context: Context, key: String): Int {
|
||||
return getPrefs(context).getInt(key, 0)
|
||||
}
|
||||
|
||||
fun getFloat(context: Context, key: String): Float {
|
||||
return getPrefs(context).getFloat(key, 0.0f)
|
||||
}
|
||||
|
||||
fun getLong(context: Context, key: String): Long {
|
||||
return getPrefs(context).getLong(key, 0L)
|
||||
}
|
||||
|
||||
fun getBoolean(context: Context, key: String): Boolean {
|
||||
return getPrefs(context).getBoolean(key, false)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.save(key: String, value: Int) {
|
||||
Preferences.putInteger(this, key, value)
|
||||
}
|
||||
|
||||
fun Fragment.save(key: String, value: Int) {
|
||||
Preferences.putInteger(requireContext(), key, value)
|
||||
}
|
||||
|
||||
fun Context.save(key: String, value: Boolean) {
|
||||
Preferences.putBoolean(this, key, value)
|
||||
}
|
||||
|
||||
fun Fragment.save(key: String, value: Boolean) {
|
||||
Preferences.putBoolean(requireContext(), key, value)
|
||||
}
|
||||
|
||||
fun Context.save(key: String, value: String) {
|
||||
Preferences.putString(this, key, value)
|
||||
}
|
||||
|
||||
fun Fragment.save(key: String, value: String) {
|
||||
Preferences.putString(requireContext(), key, value)
|
||||
}
|
||||
53
app/src/main/java/com/aurora/store/util/Util.java
Normal file
53
app/src/main/java/com/aurora/store/util/Util.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Util {
|
||||
|
||||
public static Map<String, String> parseResponse(String response) {
|
||||
Map<String, String> keyValueMap = new HashMap<String, String>();
|
||||
StringTokenizer st = new StringTokenizer(response, "\n\r");
|
||||
while (st.hasMoreTokens()) {
|
||||
String[] keyValue = st.nextToken().split("=", 2);
|
||||
if (keyValue.length >= 2) {
|
||||
keyValueMap.put(keyValue[0], keyValue[1]);
|
||||
}
|
||||
}
|
||||
return keyValueMap;
|
||||
}
|
||||
|
||||
public static Map<String, String> parseCookieString(String cookies) {
|
||||
Map<String, String> cookieList = new HashMap<>();
|
||||
Pattern cookiePattern = Pattern.compile("([^=]+)=([^;]*);?\\s?");
|
||||
Matcher matcher = cookiePattern.matcher(cookies);
|
||||
while (matcher.find()) {
|
||||
String cookieKey = matcher.group(1);
|
||||
String cookieValue = matcher.group(2);
|
||||
cookieList.put(cookieKey, cookieValue);
|
||||
}
|
||||
return cookieList;
|
||||
}
|
||||
}
|
||||
71
app/src/main/java/com/aurora/store/util/ViewUtil.kt
Normal file
71
app/src/main/java/com/aurora/store/util/ViewUtil.kt
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
|
||||
|
||||
object ViewUtil {
|
||||
|
||||
fun getEmptyActivityBundle(context: Context?): Bundle? {
|
||||
return ActivityOptionsCompat.makeCustomAnimation(
|
||||
context!!,
|
||||
android.R.anim.fade_in,
|
||||
android.R.anim.fade_out
|
||||
).toBundle()
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
fun configureActivityLayout(activity: Activity, isLight: Boolean) {
|
||||
val window = activity.window
|
||||
val params = window.attributes
|
||||
params.flags = params.flags and WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
|
||||
window.attributes = params
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
setFullScreenLightStatusBar(activity, isLight)
|
||||
}
|
||||
|
||||
private fun setFullScreenLightStatusBar(activity: Activity, isLight: Boolean) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
var flags = activity.window.decorView.systemUiVisibility
|
||||
if (isLight)
|
||||
flags = flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
||||
flags = flags or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
flags = flags or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
activity.window.decorView.systemUiVisibility = flags
|
||||
}
|
||||
}
|
||||
|
||||
fun getStyledAttribute(context: Context, styleID: Int): Int {
|
||||
val arr = context.obtainStyledAttributes(TypedValue().data, intArrayOf(styleID))
|
||||
val styledColor = arr.getColor(0, Color.WHITE)
|
||||
arr.recycle()
|
||||
return styledColor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
fun <T> MutableList<T>.flushAndAdd(list: List<T>) {
|
||||
clear()
|
||||
addAll(list)
|
||||
}
|
||||
|
||||
fun <T> MutableSet<T>.flushAndAdd(list: Set<T>) {
|
||||
clear()
|
||||
addAll(list)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
import android.os.Build
|
||||
import android.text.format.DateFormat
|
||||
import java.util.*
|
||||
|
||||
fun Long.toDate(): String {
|
||||
val calendar = Calendar.getInstance(Locale.getDefault())
|
||||
calendar.timeInMillis = this
|
||||
return DateFormat.format("dd/MM/yy", calendar).toString()
|
||||
}
|
||||
|
||||
fun isLAndAbove(): Boolean {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||
}
|
||||
|
||||
fun isNAndAbove(): Boolean {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
|
||||
}
|
||||
|
||||
fun isPAndAbove(): Boolean {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
|
||||
}
|
||||
|
||||
fun isQAndAbove(): Boolean {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
||||
}
|
||||
114
app/src/main/java/com/aurora/store/util/extensions/Context.kt
Normal file
114
app/src/main/java/com/aurora/store/util/extensions/Context.kt
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ShareCompat
|
||||
import com.aurora.Constants
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.store.MainActivity
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.ViewUtil
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
|
||||
fun Context.browse(url: String) {
|
||||
try {
|
||||
startActivity(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse(url)
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.share(app: App) {
|
||||
try {
|
||||
ShareCompat.IntentBuilder.from(this as AppCompatActivity)
|
||||
.setType("text/plain")
|
||||
.setChooserTitle(getString(R.string.action_share))
|
||||
.setSubject(app.displayName)
|
||||
.setText(Constants.SHARE_URL + app.packageName)
|
||||
.startChooser()
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.openInfo(packageName: String) {
|
||||
try {
|
||||
val intent = Intent(
|
||||
"android.settings.APPLICATION_DETAILS_SETTINGS",
|
||||
Uri.parse("package:$packageName")
|
||||
)
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Context.open(className: Class<T>, newTask: Boolean = false) {
|
||||
val intent = Intent(this, className)
|
||||
if (newTask)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
startActivity(
|
||||
intent,
|
||||
ViewUtil.getEmptyActivityBundle(this)
|
||||
)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.close() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
finishAfterTransition()
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.restartApp() {
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
this,
|
||||
1337,
|
||||
Intent(this, MainActivity::class.java),
|
||||
PendingIntent.FLAG_CANCEL_CURRENT
|
||||
)
|
||||
|
||||
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent)
|
||||
exitProcess(0)
|
||||
}
|
||||
|
||||
fun Context.copyToClipBoard(data: String?) {
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Download Url", data)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
}
|
||||
165
app/src/main/java/com/aurora/store/util/extensions/Glide.kt
Normal file
165
app/src/main/java/com/aurora/store/util/extensions/Glide.kt
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.RawRes
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.TransitionOptions
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.ViewTarget
|
||||
import com.bumptech.glide.request.transition.DrawableCrossFadeFactory
|
||||
import java.io.File
|
||||
|
||||
fun ImageView.load(
|
||||
bitmap: Bitmap?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions? = null
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(bitmap, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
fun ImageView.load(
|
||||
byteArray: ByteArray?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions? = null
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(byteArray, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
fun ImageView.load(
|
||||
drawable: Drawable?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions? = null
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(drawable, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
fun ImageView.load(
|
||||
@RawRes @DrawableRes resourceId: Int?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions? = null
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(resourceId, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
fun ImageView.load(
|
||||
uri: Uri?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions? = null
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(uri, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
fun ImageView.load(
|
||||
string: String?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions? = null
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(string, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
fun ImageView.load(
|
||||
file: File?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions? = null
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(file, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun ImageView.load(
|
||||
bitmap: Bitmap?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions.() -> Unit
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(bitmap, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun ImageView.load(
|
||||
byteArray: ByteArray?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions.() -> Unit
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(byteArray, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun ImageView.load(
|
||||
drawable: Drawable?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions.() -> Unit
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(drawable, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun ImageView.load(
|
||||
@RawRes @DrawableRes resourceId: Int?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions.() -> Unit
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(resourceId, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun ImageView.load(
|
||||
uri: Uri?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions.() -> Unit
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(uri, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun ImageView.load(
|
||||
string: String?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions.() -> Unit
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(string, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun ImageView.load(
|
||||
file: File?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions.() -> Unit
|
||||
): ViewTarget<ImageView, Drawable> = loadAny(file, transitionOptions, requestOptions)
|
||||
|
||||
@JvmSynthetic
|
||||
fun ImageView.loadAny(
|
||||
data: Any?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions? = null
|
||||
): ViewTarget<ImageView, Drawable> {
|
||||
return Glide.with(this)
|
||||
.load(data)
|
||||
.apply {
|
||||
transitionOptions?.let { transition(it) }
|
||||
requestOptions?.let { apply(it) }
|
||||
}
|
||||
.into(this)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun ImageView.loadAny(
|
||||
data: Any?,
|
||||
transitionOptions: TransitionOptions<*, Drawable>? = null,
|
||||
requestOptions: RequestOptions.() -> Unit
|
||||
): ViewTarget<ImageView, Drawable> {
|
||||
val factory = DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build()
|
||||
return Glide.with(this)
|
||||
.load(data)
|
||||
.transition(withCrossFade(factory))
|
||||
.apply(RequestOptions().apply(requestOptions))
|
||||
.into(this)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
fun ImageView.clear() {
|
||||
//Glide.with(this).clear(this)
|
||||
}
|
||||
28
app/src/main/java/com/aurora/store/util/extensions/Number.kt
Normal file
28
app/src/main/java/com/aurora/store/util/extensions/Number.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
import android.content.res.Resources
|
||||
|
||||
val Number.dp: Number
|
||||
get() = (this.toFloat() / Resources.getSystem().displayMetrics.density).toInt()
|
||||
|
||||
val Number.px: Number
|
||||
get() = (this.toFloat() * Resources.getSystem().displayMetrics.density).toInt()
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.WindowInsetsController
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.aurora.Constants
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.util.CommonUtil
|
||||
import com.aurora.store.util.ViewUtil
|
||||
|
||||
|
||||
fun Fragment.applyTheme(
|
||||
themeId: Int,
|
||||
accentId: Int = 1,
|
||||
shouldApplyTransition: Boolean = true,
|
||||
position: Int = 2
|
||||
) {
|
||||
val themeStyle = CommonUtil.getThemeStyleById(themeId)
|
||||
|
||||
if (themeStyle == 0) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
(requireActivity() as AppCompatActivity).applyDayNightMask()
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
}
|
||||
|
||||
/*Apply Theme*/
|
||||
requireContext().theme.applyStyle(themeStyle, true)
|
||||
|
||||
/*Apply transition only on AppCompatActivity*/
|
||||
if (shouldApplyTransition)
|
||||
(requireActivity() as AppCompatActivity).transitionRecreate(position)
|
||||
else
|
||||
(requireActivity() as AppCompatActivity).recreate()
|
||||
|
||||
if (themeId == 1) {
|
||||
(requireActivity() as AppCompatActivity).setLightConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
fun AppCompatActivity.transitionRecreate(position: Int = 2) {
|
||||
val intent = Intent(this, javaClass)
|
||||
intent.putExtra(Constants.INT_EXTRA, position)
|
||||
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
startActivity(intent)
|
||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.applyTheme(themeId: Int, accentId: Int = 1) {
|
||||
val themeStyle = CommonUtil.getThemeStyleById(themeId)
|
||||
val accentStyle = CommonUtil.getAccentStyleById(accentId)
|
||||
|
||||
if (themeStyle == 0) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
applyDayNightMask()
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
}
|
||||
|
||||
/*Apply Theme*/
|
||||
setTheme(themeStyle)
|
||||
|
||||
/*Apply Accent*/
|
||||
theme.applyStyle(accentStyle, true)
|
||||
|
||||
/*Apply Light Configuration*/
|
||||
if (themeId == 1) {
|
||||
setLightConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
fun AppCompatActivity.applyDayNightMask() {
|
||||
val currentNightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||
if (currentNightMode == Configuration.UI_MODE_NIGHT_NO) {
|
||||
setLightConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
fun AppCompatActivity.setLightConfiguration() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
setLightConfigurationO()
|
||||
} else {
|
||||
setLightConfigurationO()
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
private fun AppCompatActivity.setLightConfigurationR() {
|
||||
window?.insetsController?.setSystemBarsAppearance(
|
||||
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
|
||||
or WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS,
|
||||
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
|
||||
)
|
||||
}
|
||||
|
||||
private fun AppCompatActivity.setLightConfigurationO() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
setLightStatusBar()
|
||||
setLightNavigationBar()
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
window.statusBarColor = ColorUtils.setAlphaComponent(Color.BLACK, 120)
|
||||
}
|
||||
}
|
||||
|
||||
private fun AppCompatActivity.setLightStatusBar() {
|
||||
var flags = window.decorView.systemUiVisibility
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
flags = flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
||||
}
|
||||
window.decorView.systemUiVisibility = flags
|
||||
}
|
||||
|
||||
private fun AppCompatActivity.setLightNavigationBar() {
|
||||
var flags = window.decorView.systemUiVisibility
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
window.navigationBarColor =
|
||||
ViewUtil.getStyledAttribute(this, android.R.attr.colorBackground)
|
||||
flags = flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
||||
}
|
||||
window.decorView.systemUiVisibility = flags
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
|
||||
fun runAsync(action: () -> Unit) = Thread(Runnable(action)).start()
|
||||
|
||||
fun runOnUiThread(action: () -> Unit) {
|
||||
if (isMainLooperAlive()) {
|
||||
action()
|
||||
} else {
|
||||
Handler(Looper.getMainLooper()).post(Runnable(action))
|
||||
}
|
||||
}
|
||||
|
||||
fun runDelayed(delayMillis: Long, action: () -> Unit) =
|
||||
Handler().postDelayed(Runnable(action), delayMillis)
|
||||
|
||||
fun runDelayedOnUiThread(delayMillis: Long, action: () -> Unit) =
|
||||
Handler(Looper.getMainLooper()).postDelayed(Runnable(action), delayMillis)
|
||||
|
||||
private fun isMainLooperAlive() = Looper.myLooper() == Looper.getMainLooper()
|
||||
36
app/src/main/java/com/aurora/store/util/extensions/Toast.kt
Normal file
36
app/src/main/java/com/aurora/store/util/extensions/Toast.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
fun Context.toast(text: CharSequence): Toast =
|
||||
Toast.makeText(this, text, Toast.LENGTH_SHORT).apply { show() }
|
||||
|
||||
fun Context.longToast(text: CharSequence): Toast =
|
||||
Toast.makeText(this, text, Toast.LENGTH_LONG).apply { show() }
|
||||
|
||||
fun Context.toast(@StringRes resId: Int): Toast =
|
||||
Toast.makeText(this, resId, Toast.LENGTH_SHORT).apply { show() }
|
||||
|
||||
fun Context.longToast(@StringRes resId: Int): Toast =
|
||||
Toast.makeText(this, resId, Toast.LENGTH_LONG).apply { show() }
|
||||
81
app/src/main/java/com/aurora/store/util/extensions/View.kt
Normal file
81
app/src/main/java/com/aurora/store/util/extensions/View.kt
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.util.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
|
||||
fun View.isVisible() = visibility == View.VISIBLE
|
||||
|
||||
fun View.isGone() = visibility == View.GONE
|
||||
|
||||
fun View.isInvisible() = visibility == View.INVISIBLE
|
||||
|
||||
fun View.show() {
|
||||
visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun View.hide() {
|
||||
visibility = View.GONE
|
||||
}
|
||||
|
||||
fun View.showKeyboard() {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
this.requestFocus()
|
||||
imm.showSoftInput(this, 0)
|
||||
}
|
||||
|
||||
fun View.hideKeyboard(): Boolean {
|
||||
try {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
return imm.hideSoftInputFromWindow(windowToken, 0)
|
||||
} catch (ignored: RuntimeException) {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun View.setOnSingleClickListener(tolerance: Long = 500, onClick: (v: View) -> Unit) {
|
||||
var lastClicked = 0L
|
||||
val currentTimeMillis = System.currentTimeMillis()
|
||||
setOnClickListener {
|
||||
if (currentTimeMillis - lastClicked > tolerance) {
|
||||
onClick(it)
|
||||
lastClicked = currentTimeMillis
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun View.rotate(resetToZero: Boolean = true, duration: Long = 400) {
|
||||
if (resetToZero)
|
||||
rotation = 0f
|
||||
animate().rotation(360f).setDuration(duration).start()
|
||||
}
|
||||
|
||||
fun View.flip(resetToZero: Boolean = true, duration: Long = 400) {
|
||||
if (resetToZero)
|
||||
rotation = 0f
|
||||
animate().rotation(180f).setDuration(duration).start()
|
||||
}
|
||||
|
||||
fun View.getString(resourceId: Int): String {
|
||||
return context.getString(resourceId)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.custom
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.databinding.ViewActionButtonBinding
|
||||
|
||||
class ActionButton : RelativeLayout {
|
||||
|
||||
private lateinit var B: ViewActionButtonBinding
|
||||
|
||||
constructor(context: Context) : super(context) {
|
||||
init(context, null)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
private fun init(context: Context, attrs: AttributeSet?) {
|
||||
val view = inflate(context, R.layout.view_action_button, this)
|
||||
B = ViewActionButtonBinding.bind(view)
|
||||
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ActionButton)
|
||||
val btnTxt = typedArray.getString(R.styleable.ActionButton_btnActionText)
|
||||
B.btn.text = btnTxt
|
||||
typedArray.recycle()
|
||||
}
|
||||
|
||||
fun setText(text: String) {
|
||||
B.btn.text = text
|
||||
}
|
||||
|
||||
fun updateProgress(isVisible: Boolean) {
|
||||
if (isVisible)
|
||||
B.progress.visibility = View.VISIBLE
|
||||
else
|
||||
|
||||
B.progress.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
fun addOnClickListener(onClickListener: OnClickListener) {
|
||||
B.btn.setOnClickListener(onClickListener)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.custom;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
public class CubicBezierInterpolator implements Interpolator {
|
||||
|
||||
public static final CubicBezierInterpolator DEFAULT = new CubicBezierInterpolator(0.25, 0.1, 0.25, 1);
|
||||
public static final CubicBezierInterpolator EASE_OUT = new CubicBezierInterpolator(0, 0, .58, 1);
|
||||
public static final CubicBezierInterpolator EASE_OUT_QUINT = new CubicBezierInterpolator(.23, 1, .32, 1);
|
||||
public static final CubicBezierInterpolator EASE_IN = new CubicBezierInterpolator(.42, 0, 1, 1);
|
||||
public static final CubicBezierInterpolator EASE_BOTH = new CubicBezierInterpolator(.42, 0, .58, 1);
|
||||
public static final CubicBezierInterpolator EASE_IN_OUT_QUAD = new CubicBezierInterpolator(0.455, 0.03, 0.515, 0.955);
|
||||
|
||||
protected PointF start;
|
||||
protected PointF end;
|
||||
protected PointF a = new PointF();
|
||||
protected PointF b = new PointF();
|
||||
protected PointF c = new PointF();
|
||||
|
||||
public CubicBezierInterpolator(PointF start, PointF end) throws IllegalArgumentException {
|
||||
if (start.x < 0 || start.x > 1) {
|
||||
throw new IllegalArgumentException("startX value must be in the range [0, 1]");
|
||||
}
|
||||
if (end.x < 0 || end.x > 1) {
|
||||
throw new IllegalArgumentException("endX value must be in the range [0, 1]");
|
||||
}
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public CubicBezierInterpolator(float startX, float startY, float endX, float endY) {
|
||||
this(new PointF(startX, startY), new PointF(endX, endY));
|
||||
}
|
||||
|
||||
public CubicBezierInterpolator(double startX, double startY, double endX, double endY) {
|
||||
this((float) startX, (float) startY, (float) endX, (float) endY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInterpolation(float time) {
|
||||
return getBezierCoordinateY(getXForTime(time));
|
||||
}
|
||||
|
||||
protected float getBezierCoordinateY(float time) {
|
||||
c.y = 3 * start.y;
|
||||
b.y = 3 * (end.y - start.y) - c.y;
|
||||
a.y = 1 - c.y - b.y;
|
||||
return time * (c.y + time * (b.y + time * a.y));
|
||||
}
|
||||
|
||||
protected float getXForTime(float time) {
|
||||
float x = time;
|
||||
float z;
|
||||
for (int i = 1; i < 14; i++) {
|
||||
z = getBezierCoordinateX(x) - time;
|
||||
if (Math.abs(z) < 1e-3) {
|
||||
break;
|
||||
}
|
||||
x -= z / getXDerivate(x);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
private float getXDerivate(float t) {
|
||||
return c.x + t * (2 * b.x + 3 * a.x * t);
|
||||
}
|
||||
|
||||
private float getBezierCoordinateX(float time) {
|
||||
c.x = 3 * start.x;
|
||||
b.x = 3 * (end.x - start.x) - c.x;
|
||||
a.x = 1 - c.x - b.x;
|
||||
return time * (c.x + time * (b.x + time * a.x));
|
||||
}
|
||||
}
|
||||
71
app/src/main/java/com/aurora/store/view/custom/RatingView.kt
Normal file
71
app/src/main/java/com/aurora/store/view/custom/RatingView.kt
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.custom
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.databinding.ViewRatingBinding
|
||||
|
||||
class RatingView : RelativeLayout {
|
||||
|
||||
private lateinit var B: ViewRatingBinding
|
||||
|
||||
var number = 0
|
||||
var max = 0
|
||||
var rating = 0
|
||||
|
||||
constructor(context: Context, number: Int, max: Int, rating: Int) : super(context) {
|
||||
this.number = number
|
||||
this.max = max
|
||||
this.rating = rating
|
||||
init(context)
|
||||
}
|
||||
|
||||
constructor(context: Context?) : super(context) {}
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
constructor(
|
||||
context: Context?,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||
}
|
||||
|
||||
private fun init(context: Context) {
|
||||
val view = inflate(context, R.layout.view_rating, this)
|
||||
B = ViewRatingBinding.bind(view)
|
||||
|
||||
B.avgNum.text = number.toString()
|
||||
B.avgRating.max = max
|
||||
B.avgRating.progress = rating
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.custom
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.databinding.ViewStateButtonBinding
|
||||
|
||||
class StateButton : RelativeLayout {
|
||||
|
||||
private lateinit var B: ViewStateButtonBinding
|
||||
|
||||
constructor(context: Context) : super(context) {
|
||||
init(context, null)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
private fun init(context: Context, attrs: AttributeSet?) {
|
||||
val view = inflate(context, R.layout.view_state_button, this)
|
||||
B = ViewStateButtonBinding.bind(view)
|
||||
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.StateButton)
|
||||
val btnTxt = typedArray.getString(R.styleable.StateButton_btnStateText)
|
||||
val btnIcon = typedArray.getResourceId(
|
||||
R.styleable.StateButton_btnStateIcon,
|
||||
R.drawable.ic_arrow_right
|
||||
)
|
||||
|
||||
B.btn.text = btnTxt
|
||||
B.btn.icon = ContextCompat.getDrawable(context, btnIcon)
|
||||
typedArray.recycle()
|
||||
}
|
||||
|
||||
fun updateProgress(isVisible: Boolean) {
|
||||
if (isVisible)
|
||||
B.progress.visibility = View.VISIBLE
|
||||
else
|
||||
|
||||
B.progress.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
fun addOnClickListener(onClickListener: OnClickListener) {
|
||||
B.btn.setOnClickListener(onClickListener)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.custom.layouts
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.databinding.ViewActionHeaderBinding
|
||||
|
||||
class ActionHeaderLayout : RelativeLayout {
|
||||
|
||||
private lateinit var B: ViewActionHeaderBinding
|
||||
|
||||
constructor(context: Context) : super(context) {
|
||||
init(context, null)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
private fun init(context: Context, attrs: AttributeSet?) {
|
||||
val view = inflate(context, R.layout.view_action_header, this)
|
||||
B = ViewActionHeaderBinding.bind(view)
|
||||
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ActionHeaderLayout)
|
||||
val textPrimary = typedArray.getString(R.styleable.ActionHeaderLayout_headerTitle)
|
||||
|
||||
textPrimary?.let {
|
||||
B.txtTitle.text = it
|
||||
}
|
||||
}
|
||||
|
||||
fun setHeader(header: String?) {
|
||||
B.txtTitle.text = header
|
||||
}
|
||||
|
||||
fun addClickListener(onclickListener: OnClickListener?) {
|
||||
B.imgAction.visibility = View.VISIBLE
|
||||
B.imgAction.setOnClickListener(onclickListener)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.custom.layouts
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.databinding.ViewDevInfoBinding
|
||||
|
||||
class ViewDevInfo : RelativeLayout {
|
||||
|
||||
private lateinit var B: ViewDevInfoBinding
|
||||
|
||||
constructor(context: Context) : super(context) {
|
||||
init(context, null)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
private fun init(context: Context, attrs: AttributeSet?) {
|
||||
val view = inflate(context, R.layout.view_dev_info, this)
|
||||
B = ViewDevInfoBinding.bind(view)
|
||||
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.DevInfoLayout)
|
||||
val icon = typedArray.getResourceId(
|
||||
R.styleable.DevInfoLayout_imgIcon,
|
||||
R.drawable.ic_map_marker
|
||||
)
|
||||
|
||||
val textPrimary = typedArray.getString(R.styleable.DevInfoLayout_txtTitle)
|
||||
val textSecondary = typedArray.getString(R.styleable.DevInfoLayout_txtSubtitle)
|
||||
|
||||
B.img.setImageResource(icon)
|
||||
B.txtTitle.text = textPrimary
|
||||
B.txtSubtitle.text = textSecondary
|
||||
typedArray.recycle()
|
||||
}
|
||||
|
||||
fun setTxtSubtitle(text: String?) {
|
||||
B.txtSubtitle.text = text
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.custom.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.ListPreference
|
||||
|
||||
class AuroraListPreference : ListPreference {
|
||||
|
||||
constructor(context: Context) : super(context) {
|
||||
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||
|
||||
}
|
||||
|
||||
override fun getPersistedString(defaultReturnValue: String?): String? {
|
||||
return getPersistedInt(-1).toString()
|
||||
}
|
||||
|
||||
override fun persistString(value: String?): Boolean {
|
||||
return persistInt(Integer.valueOf(value))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.custom.recycler
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.OrientationHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener {
|
||||
|
||||
private var enabled = true
|
||||
private var previousTotal = 0
|
||||
private var isLoading = true
|
||||
private var visibleThreshold = RecyclerView.NO_POSITION
|
||||
|
||||
var firstVisibleItem: Int = 0
|
||||
private set
|
||||
var visibleItemCount: Int = 0
|
||||
private set
|
||||
var totalItemCount: Int = 0
|
||||
private set
|
||||
|
||||
private var isOrientationHelperVertical: Boolean = false
|
||||
private var orientationHelper: OrientationHelper? = null
|
||||
|
||||
var currentPage = 0
|
||||
private set
|
||||
|
||||
lateinit var layoutManager: RecyclerView.LayoutManager
|
||||
private set
|
||||
|
||||
constructor()
|
||||
|
||||
constructor(layoutManager: RecyclerView.LayoutManager) {
|
||||
this.layoutManager = layoutManager
|
||||
}
|
||||
|
||||
constructor(visibleThreshold: Int) {
|
||||
this.visibleThreshold = visibleThreshold
|
||||
}
|
||||
|
||||
constructor(layoutManager: RecyclerView.LayoutManager, visibleThreshold: Int) {
|
||||
this.layoutManager = layoutManager
|
||||
this.visibleThreshold = visibleThreshold
|
||||
}
|
||||
|
||||
private fun findFirstVisibleItemPosition(recyclerView: RecyclerView): Int {
|
||||
val child = findOneVisibleChild(0, layoutManager.childCount, false, true)
|
||||
return if (child == null) RecyclerView.NO_POSITION else recyclerView.getChildAdapterPosition(
|
||||
child
|
||||
)
|
||||
}
|
||||
|
||||
private fun findLastVisibleItemPosition(recyclerView: RecyclerView): Int {
|
||||
val child = findOneVisibleChild(recyclerView.childCount - 1, -1, false, true)
|
||||
return if (child == null) RecyclerView.NO_POSITION else recyclerView.getChildAdapterPosition(
|
||||
child
|
||||
)
|
||||
}
|
||||
|
||||
private fun findOneVisibleChild(
|
||||
fromIndex: Int,
|
||||
toIndex: Int,
|
||||
completelyVisible: Boolean,
|
||||
acceptPartiallyVisible: Boolean
|
||||
): View? {
|
||||
if (layoutManager.canScrollVertically() != isOrientationHelperVertical || orientationHelper == null) {
|
||||
isOrientationHelperVertical = layoutManager.canScrollVertically()
|
||||
orientationHelper = if (isOrientationHelperVertical)
|
||||
OrientationHelper.createVerticalHelper(layoutManager)
|
||||
else
|
||||
OrientationHelper.createHorizontalHelper(layoutManager)
|
||||
}
|
||||
|
||||
val mOrientationHelper = this.orientationHelper ?: return null
|
||||
|
||||
val start = mOrientationHelper.startAfterPadding
|
||||
val end = mOrientationHelper.endAfterPadding
|
||||
val next = if (toIndex > fromIndex) 1 else -1
|
||||
var partiallyVisible: View? = null
|
||||
var i = fromIndex
|
||||
while (i != toIndex) {
|
||||
val child = layoutManager.getChildAt(i)
|
||||
if (child != null) {
|
||||
val childStart = mOrientationHelper.getDecoratedStart(child)
|
||||
val childEnd = mOrientationHelper.getDecoratedEnd(child)
|
||||
if (childStart < end && childEnd > start) {
|
||||
if (completelyVisible) {
|
||||
if (childStart >= start && childEnd <= end) {
|
||||
return child
|
||||
} else if (acceptPartiallyVisible && partiallyVisible == null) {
|
||||
partiallyVisible = child
|
||||
}
|
||||
} else {
|
||||
return child
|
||||
}
|
||||
}
|
||||
}
|
||||
i += next
|
||||
}
|
||||
return partiallyVisible
|
||||
}
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
if (enabled) {
|
||||
if (!::layoutManager.isInitialized) {
|
||||
layoutManager = recyclerView.layoutManager
|
||||
?: throw RuntimeException("A LayoutManager is required")
|
||||
}
|
||||
|
||||
|
||||
if (visibleThreshold == RecyclerView.NO_POSITION) {
|
||||
visibleThreshold =
|
||||
findLastVisibleItemPosition(recyclerView) - findFirstVisibleItemPosition(
|
||||
recyclerView
|
||||
)
|
||||
}
|
||||
|
||||
visibleItemCount = recyclerView.childCount
|
||||
totalItemCount = layoutManager.itemCount
|
||||
firstVisibleItem = findFirstVisibleItemPosition(recyclerView)
|
||||
|
||||
if (isLoading) {
|
||||
if (totalItemCount > previousTotal) {
|
||||
isLoading = false
|
||||
previousTotal = totalItemCount
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLoading && totalItemCount - visibleItemCount <= firstVisibleItem + visibleThreshold) {
|
||||
currentPage++
|
||||
onLoadMore(currentPage)
|
||||
isLoading = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun enable(): EndlessRecyclerOnScrollListener {
|
||||
enabled = true
|
||||
return this
|
||||
}
|
||||
|
||||
fun disable(): EndlessRecyclerOnScrollListener {
|
||||
enabled = false
|
||||
return this
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun resetPageCount(page: Int = 0) {
|
||||
previousTotal = 0
|
||||
isLoading = true
|
||||
currentPage = page
|
||||
onLoadMore(currentPage)
|
||||
}
|
||||
|
||||
abstract fun onLoadMore(currentPage: Int)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.controller
|
||||
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
|
||||
class CategoryCarouselController(callbacks: Callbacks) : GenericCarouselController(callbacks) {
|
||||
|
||||
override fun applyFilter(streamBundle: StreamCluster): Boolean {
|
||||
return streamBundle.clusterAppList.isNotEmpty() //Filter empty clusters
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.controller
|
||||
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
|
||||
class EarlyAccessCarouselController(callbacks: Callbacks) : GenericCarouselController(callbacks) {
|
||||
|
||||
override fun applyFilter(streamBundle: StreamCluster): Boolean {
|
||||
return streamBundle.clusterTitle.isNotBlank() //Filter noisy cluster
|
||||
&& streamBundle.clusterAppList.isNotEmpty() //Filter empty clusters
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.controller
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.aurora.gplayapi.data.models.editor.EditorChoiceBundle
|
||||
import com.aurora.gplayapi.data.models.editor.EditorChoiceCluster
|
||||
import com.aurora.store.view.epoxy.groups.EditorChoiceModelGroup
|
||||
import com.aurora.store.view.epoxy.views.EditorHeadViewModel_
|
||||
|
||||
class EditorChoiceController(private val callbacks: Callbacks) :
|
||||
TypedEpoxyController<List<EditorChoiceBundle>>() {
|
||||
|
||||
interface Callbacks {
|
||||
fun onClick(editorChoiceCluster: EditorChoiceCluster)
|
||||
}
|
||||
|
||||
override fun buildModels(editorChoiceBundles: List<EditorChoiceBundle>) {
|
||||
editorChoiceBundles.forEach { editorChoiceBundle ->
|
||||
val idPrefix = editorChoiceBundle.id
|
||||
|
||||
add(
|
||||
EditorHeadViewModel_()
|
||||
.id("header_${idPrefix}")
|
||||
.title(editorChoiceBundle.bundleTitle)
|
||||
)
|
||||
|
||||
editorChoiceBundle.bundleChoiceClusters.forEach {
|
||||
add(EditorChoiceModelGroup(it, callbacks))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.gara.store.view.epoxy.controller
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.flexbox.FlexboxLayoutManager
|
||||
|
||||
class FlexLayoutManager : FlexboxLayoutManager {
|
||||
constructor(context: Context?) : super(context)
|
||||
constructor(context: Context?, flexDirection: Int) : super(context, flexDirection)
|
||||
constructor(context: Context?, flexDirection: Int, flexWrap: Int) : super(
|
||||
context,
|
||||
flexDirection,
|
||||
flexWrap
|
||||
)
|
||||
|
||||
constructor(
|
||||
context: Context?,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes)
|
||||
|
||||
override fun generateLayoutParams(lp: ViewGroup.LayoutParams): RecyclerView.LayoutParams {
|
||||
return LayoutParams(lp)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.controller
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.StreamBundle
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.view.epoxy.groups.CarouselModelGroup
|
||||
import com.aurora.store.view.epoxy.groups.CarouselShimmerGroup
|
||||
import com.aurora.store.view.epoxy.views.AppListViewModel_
|
||||
import com.aurora.store.view.epoxy.views.AppProgressViewModel_
|
||||
import com.aurora.store.view.epoxy.views.app.NoAppViewModel_
|
||||
|
||||
open class GenericCarouselController(private val callbacks: Callbacks) :
|
||||
|
||||
TypedEpoxyController<StreamBundle?>() {
|
||||
|
||||
interface Callbacks {
|
||||
fun onHeaderClicked(streamCluster: StreamCluster)
|
||||
fun onClusterScrolled(streamCluster: StreamCluster)
|
||||
fun onAppClick(app: App)
|
||||
fun onAppLongClick(app: App)
|
||||
}
|
||||
|
||||
open fun applyFilter(streamBundle: StreamCluster): Boolean {
|
||||
return streamBundle.clusterTitle.isNotBlank() //Filter noisy cluster
|
||||
&& streamBundle.clusterAppList.isNotEmpty() //Filter empty clusters
|
||||
&& streamBundle.clusterAppList.count() > 1 //Filter clusters with single apps (mostly promotions)
|
||||
}
|
||||
|
||||
override fun buildModels(streamBundle: StreamBundle?) {
|
||||
setFilterDuplicates(true)
|
||||
if (streamBundle == null) {
|
||||
for (i in 1..2) {
|
||||
add(
|
||||
CarouselShimmerGroup()
|
||||
.id(i)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (streamBundle.streamClusters.isEmpty()) {
|
||||
add(
|
||||
NoAppViewModel_()
|
||||
.id("no_app")
|
||||
.icon(R.drawable.ic_apps)
|
||||
.message("No apps available")
|
||||
)
|
||||
} else {
|
||||
if (streamBundle.streamClusters.size == 1) {
|
||||
streamBundle
|
||||
.streamClusters
|
||||
.values
|
||||
.filter { applyFilter(it) }
|
||||
.forEach { streamCluster ->
|
||||
streamCluster.clusterAppList.forEach {
|
||||
add(
|
||||
AppListViewModel_()
|
||||
.id(it.id)
|
||||
.app(it)
|
||||
.click { _ -> callbacks.onAppClick(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
streamBundle
|
||||
.streamClusters
|
||||
.values
|
||||
.filter { applyFilter(it) }
|
||||
.forEach { streamCluster ->
|
||||
add(CarouselModelGroup(streamCluster, callbacks))
|
||||
}
|
||||
|
||||
}
|
||||
if (streamBundle.hasNext())
|
||||
add(
|
||||
AppProgressViewModel_()
|
||||
.id("progress")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.groups
|
||||
|
||||
import android.content.Context
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.airbnb.epoxy.Carousel
|
||||
import com.airbnb.epoxy.ModelView
|
||||
|
||||
@ModelView(saveViewState = true, autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
|
||||
class CarouselHorizontal(context: Context?) : Carousel(context) {
|
||||
|
||||
override fun createLayoutManager(): LayoutManager {
|
||||
return LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
}
|
||||
|
||||
override fun getSnapHelperFactory(): Nothing? = null
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.groups
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModel
|
||||
import com.airbnb.epoxy.EpoxyModelGroup
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.view.epoxy.controller.GenericCarouselController
|
||||
import com.aurora.store.view.epoxy.views.AppProgressViewModel_
|
||||
import com.aurora.store.view.epoxy.views.AppViewModel_
|
||||
import com.aurora.store.view.epoxy.views.HeaderViewModel_
|
||||
|
||||
class CarouselModelGroup(
|
||||
streamCluster: StreamCluster,
|
||||
callbacks: GenericCarouselController.Callbacks
|
||||
) :
|
||||
EpoxyModelGroup(
|
||||
R.layout.model_carousel_group, buildModels(
|
||||
streamCluster,
|
||||
callbacks
|
||||
)
|
||||
) {
|
||||
companion object {
|
||||
private fun buildModels(
|
||||
streamCluster: StreamCluster,
|
||||
callbacks: GenericCarouselController.Callbacks
|
||||
): List<EpoxyModel<*>> {
|
||||
val models = ArrayList<EpoxyModel<*>>()
|
||||
val clusterViewModels = mutableListOf<EpoxyModel<*>>()
|
||||
|
||||
val idPrefix = streamCluster.id
|
||||
|
||||
models.add(
|
||||
HeaderViewModel_()
|
||||
.id("${idPrefix}_header")
|
||||
.title(streamCluster.clusterTitle)
|
||||
.browseUrl(streamCluster.clusterBrowseUrl)
|
||||
.click { _ ->
|
||||
callbacks.onHeaderClicked(streamCluster)
|
||||
}
|
||||
)
|
||||
|
||||
for (app in streamCluster.clusterAppList) {
|
||||
clusterViewModels.add(
|
||||
AppViewModel_()
|
||||
.id(app.id)
|
||||
.app(app)
|
||||
.click { _ ->
|
||||
callbacks.onAppClick(app)
|
||||
}
|
||||
.longClick { _ ->
|
||||
callbacks.onAppLongClick(app)
|
||||
false
|
||||
}
|
||||
.onBind { _, _, position ->
|
||||
val itemCount = clusterViewModels.count()
|
||||
if (itemCount >= 2) {
|
||||
if (position == clusterViewModels.count() - 2) {
|
||||
callbacks.onClusterScrolled(streamCluster)
|
||||
Log.i("Cluster %s Scrolled", streamCluster.clusterTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (streamCluster.hasNext()) {
|
||||
clusterViewModels.add(
|
||||
AppProgressViewModel_()
|
||||
.id("${idPrefix}_progress")
|
||||
)
|
||||
}
|
||||
|
||||
models.add(
|
||||
CarouselHorizontalModel_()
|
||||
.id("${idPrefix}_cluster")
|
||||
.models(clusterViewModels)
|
||||
)
|
||||
|
||||
return models
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.groups
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModel
|
||||
import com.airbnb.epoxy.EpoxyModelGroup
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.view.epoxy.views.shimmer.AppViewShimmerModel_
|
||||
import com.aurora.store.view.epoxy.views.shimmer.HeaderViewShimmerModel_
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class CarouselShimmerGroup() :
|
||||
EpoxyModelGroup(
|
||||
R.layout.model_carousel_group, buildModels()
|
||||
) {
|
||||
companion object {
|
||||
private fun buildModels(): List<EpoxyModel<*>> {
|
||||
val models = ArrayList<EpoxyModel<*>>()
|
||||
val clusterViewModels = mutableListOf<EpoxyModel<*>>()
|
||||
val idPrefix = UUID.randomUUID()
|
||||
|
||||
for (i in 1..8) {
|
||||
clusterViewModels.add(
|
||||
AppViewShimmerModel_()
|
||||
.id(i)
|
||||
)
|
||||
}
|
||||
|
||||
models.add(
|
||||
HeaderViewShimmerModel_()
|
||||
.id("shimmer_header")
|
||||
)
|
||||
|
||||
models.add(
|
||||
CarouselHorizontalModel_()
|
||||
.id("cluster_${idPrefix}")
|
||||
.models(clusterViewModels)
|
||||
)
|
||||
return models
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.groups
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModel
|
||||
import com.airbnb.epoxy.EpoxyModelGroup
|
||||
import com.aurora.gplayapi.data.models.editor.EditorChoiceCluster
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.view.epoxy.controller.EditorChoiceController
|
||||
import com.aurora.store.view.epoxy.views.EditorImageViewModel_
|
||||
import com.aurora.store.view.epoxy.views.HeaderViewModel_
|
||||
|
||||
class EditorChoiceModelGroup(
|
||||
editorChoiceCluster: EditorChoiceCluster,
|
||||
callbacks: EditorChoiceController.Callbacks
|
||||
) :
|
||||
EpoxyModelGroup(
|
||||
R.layout.model_editorchoice_group, buildModels(
|
||||
editorChoiceCluster,
|
||||
callbacks
|
||||
)
|
||||
) {
|
||||
companion object {
|
||||
private fun buildModels(
|
||||
editorChoiceCluster: EditorChoiceCluster,
|
||||
callbacks: EditorChoiceController.Callbacks
|
||||
): List<EpoxyModel<*>> {
|
||||
|
||||
val models = ArrayList<EpoxyModel<*>>()
|
||||
val clusterViewModels = mutableListOf<EpoxyModel<*>>()
|
||||
|
||||
val idPrefix = editorChoiceCluster.id
|
||||
|
||||
models.add(
|
||||
HeaderViewModel_()
|
||||
.id("header_${idPrefix}")
|
||||
.title(editorChoiceCluster.clusterTitle)
|
||||
.browseUrl(editorChoiceCluster.clusterBrowseUrl)
|
||||
.click { _ -> callbacks.onClick(editorChoiceCluster) }
|
||||
)
|
||||
|
||||
editorChoiceCluster.clusterArtwork.forEach {
|
||||
clusterViewModels.add(
|
||||
EditorImageViewModel_()
|
||||
.id("artwork_${idPrefix}")
|
||||
.artwork(it)
|
||||
)
|
||||
}
|
||||
|
||||
models.add(
|
||||
CarouselHorizontalModel_()
|
||||
.id("cluster_${idPrefix}")
|
||||
.models(clusterViewModels)
|
||||
)
|
||||
|
||||
return models
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.views
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.CallbackProp
|
||||
import com.airbnb.epoxy.ModelProp
|
||||
import com.airbnb.epoxy.ModelView
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.model.Accent
|
||||
import com.aurora.store.databinding.ViewAccentBinding
|
||||
|
||||
@ModelView(
|
||||
autoLayout = ModelView.Size.WRAP_WIDTH_WRAP_HEIGHT,
|
||||
baseModelClass = BaseView::class
|
||||
)
|
||||
class AccentView : RelativeLayout {
|
||||
|
||||
private lateinit var B: ViewAccentBinding
|
||||
|
||||
constructor(context: Context?) : super(context) {
|
||||
init(context, null)
|
||||
}
|
||||
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
private fun init(context: Context?, attrs: AttributeSet?) {
|
||||
val view = inflate(context, R.layout.view_accent, this)
|
||||
B = ViewAccentBinding.bind(view)
|
||||
}
|
||||
|
||||
@ModelProp
|
||||
fun accent(accent: Accent) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
||||
B.img.backgroundTintList = ColorStateList.valueOf(Color.parseColor(accent.accent))
|
||||
} else {
|
||||
B.img.setBackgroundColor(Color.parseColor(accent.accent))
|
||||
}
|
||||
}
|
||||
|
||||
@ModelProp
|
||||
fun markChecked(isChecked: Boolean) {
|
||||
B.tick.isVisible = isChecked
|
||||
}
|
||||
|
||||
@CallbackProp
|
||||
fun click(onClickListener: OnClickListener?) {
|
||||
B.root.setOnClickListener(onClickListener)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user