@ -0,0 +1 @@
|
||||
/build
|
||||
@ -0,0 +1,50 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.galaxy.pin"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.galaxy.oceen"
|
||||
minSdk = 24
|
||||
targetSdk = 33
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_20
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "20"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
// implementation("androidx.activity:activity-ktx:1.10.1")
|
||||
// implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.appcompat:appcompat:1.7.0")
|
||||
// implementation("com.google.android.material:material:1.12.0")
|
||||
// implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.2.1")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
|
||||
implementation(project(":lib"))
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
# 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
|
||||
|
||||
-dontoptimize
|
||||
@ -0,0 +1,41 @@
|
||||
package com.galaxy.pin
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
import java.net.CookieManager
|
||||
import java.net.URI
|
||||
|
||||
/**
|
||||
* 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.galaxy.pin", appContext.packageName)
|
||||
}
|
||||
|
||||
//"set-cookie":["_ga=GA1.2.9752596038.1758536285; expires=Sat, 21 Mar 2026 10:18:16 GMT; Max-Age=15552000; path=\/; HttpOnly","ng_session=eyJpdiI6Im1PaSsycnFvYUNFR2NyYnoyeVBhM0E9PSIsInZhbHVlIjoidW94QWhXSnBYSDZlWnkzTW1MWFI5aEx4eTJ1NkxVMU9YZVhQWG5mWlY5bW05bDhjcTRzdUJEMDRlWEo1WDV1eVNuSHIxbkpQZVAwVGlWbnIxVlRjYTBGLzJuRFE2bUNkckJkY254bTRmQ2czSVBQNWlsUnZsb3dFd1RqVWVpZ2wiLCJtYWMiOiJkNzE4ODhkYmY1MDQ5Y2U4ODlkZWM5ZDAxYzU1YTM4NjdlZDQ0NTdkNTJkNzlhM2FjNDNhMDczMTRiZDIxOTY0IiwidGFnIjoiIn0%3D; expires=Mon, 22 Sep 2025 16:18:16 GMT; Max-Age=21600; path=\/; httponly; samesite=lax","userPermID=eyJpdiI6Im44KzlKajBtV1R1clNmTXc0bzJxS3c9PSIsInZhbHVlIjoiWnhmcEJuMjczRTUvZy9pRVF0R081QzhYdUFaNFdJTFkvU0NmTUJPVEZSTXFDcDBzR0MvdDJGZlNtVUZibEh5VkJvajdYTWxGa2hKTTVYUW01ekdzSUhSOG9EK2pzdUFmbTV3aWhhWlR0aXM9IiwibWFjIjoiMzg5NGYzM2JiMzc3ZjUwMzgwMDA3MjM3YmIzNjk1MTdiMDAzNDM0MWI3NDMwYzQwNGE3MjI4ZWZhOTA4M2IxOCIsInRhZyI6IiJ9; expires=Thu, 20 Sep 2035 10:18:16 GMT; Max-Age=315360000; path=\/; httponly; samesite=lax","userSessionID=eyJpdiI6InViVGJSRkJuMWpkbFdOV3lYcFQ0Zmc9PSIsInZhbHVlIjoiSlVCVXMzbml4L1dQd0k5SmRvZE9oQVl2Q3BVQXNobTY3Sy83RnhUTU5XQVUrUmZkUlBqMXZFZGdvRHhEbnFrYy92SGZockdSOTZmSkpVMk9jQTJpMERFV3pOWE5UMndnNXNvV2xEM3RRbms9IiwibWFjIjoiYjMzMDg2N2Q1YWRkMDgzZTVkMzNiM2YzM2FiZjc3NGUwZmY5YmJiNGJkNmFkMTNhZjgwN2M2MmFlYzdkZWE3MSIsInRhZyI6IiJ9; expires=Mon, 22 Sep 2025 10:48:16 GMT; Max-Age=1800; path=\/; httponly; samesite=lax","ctxid=eyJpdiI6IjYxckdtcUhsM2taYXBtdmhHYXBxNGc9PSIsInZhbHVlIjoiQ2ZTTndBRldvMTQyYnRVYTBaelJLU0RtSFdtakJGL2tCa0RrWHk1M3NqNGdGRGxydEl6aURXMUFtWVNSVWY4My9wOHdDVDFMS0JLSXhQTDZuaFpIc1Vtb1F3c1FwTTZCZ083SmVncTExUmc9IiwibWFjIjoiOTdmMTkwODY0MTMzNGQ3MGE2NmFiOTA0NTc3ZDY1NDViMTg5NGZlNGFjOTRlZDg0ZjllNmNhMzZhODkzZTE3MSIsInRhZyI6IiJ9; expires=Thu, 20 Sep 2035 10:18:16 GMT; Max-Age=315360000; path=\/; httponly; samesite=lax","rd=deleted; expires=Sun, 22 Sep 2024 10:18:15 GMT; Max-Age=0; path=\/; httponly; samesite=lax","TS01e2a186=01b02e3e89ffd23eb296837770eb3f0b25fd04d8e5aa8ad77aa8330e586a67e45f47ef68922e78171195ef9071c878ff860388ea3e; Path=\/; Domain=.ng-app.com;"]
|
||||
@Test
|
||||
fun cookie() {
|
||||
val url = URI("http://ng-app.com")
|
||||
val set_cookie = listOf("_ga=GA1.2.9752596038.1758536285; expires=Sat, 26 Mar 2026 10:18:16 GMT; Max-Age=15552000; path=\\/; HttpOnly")
|
||||
val cookieManager = CookieManager()
|
||||
cookieManager.put(url, mapOf("Set-Cookie" to set_cookie))
|
||||
val cookies = cookieManager.get(URI("http://ng-app.com"), mutableMapOf()).get("Cookie")
|
||||
println("cookies: $cookies")
|
||||
|
||||
// HttpCookie.parse("rd=deleted; expires=Thu, 25 Sep 2025 14:48:12 GMT; Max-Age=0; path=\\/; httponly; samesite=lax")
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,567 @@
|
||||
package com.galaxy.pin;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public final class HttpCookie implements Cloneable {
|
||||
private final String name;
|
||||
private String value;
|
||||
private String comment;
|
||||
private String commentURL;
|
||||
private boolean toDiscard;
|
||||
private String domain;
|
||||
private long maxAge;
|
||||
private String path;
|
||||
private String portlist;
|
||||
private boolean secure;
|
||||
private boolean httpOnly;
|
||||
private int version;
|
||||
private final String header;
|
||||
private final long whenCreated;
|
||||
private static final long MAX_AGE_UNSPECIFIED = -1L;
|
||||
private static final String[] COOKIE_DATE_FORMATS = new String[]{"EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'", "EEE',' dd MMM yyyy HH:mm:ss 'GMT'", "EEE MMM dd yyyy HH:mm:ss 'GMT'Z", "EEE',' dd-MMM-yy HH:mm:ss 'GMT'", "EEE',' dd MMM yy HH:mm:ss 'GMT'", "EEE MMM dd yy HH:mm:ss 'GMT'Z"};
|
||||
private static final String SET_COOKIE = "set-cookie:";
|
||||
private static final String SET_COOKIE2 = "set-cookie2:";
|
||||
private static final String tspecials = ",; ";
|
||||
static final Map<String, CookieAttributeAssignor> assignors = new HashMap();
|
||||
static final TimeZone GMT;
|
||||
|
||||
public HttpCookie(String var1, String var2) {
|
||||
this(var1, var2, (String)null);
|
||||
}
|
||||
|
||||
private HttpCookie(String var1, String var2, String var3) {
|
||||
this(var1, var2, var3, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
HttpCookie(String var1, String var2, String var3, long var4) {
|
||||
this.maxAge = -1L;
|
||||
this.version = 1;
|
||||
var1 = var1.trim();
|
||||
if (!var1.isEmpty() && isToken(var1) && var1.charAt(0) != '$') {
|
||||
this.name = var1;
|
||||
this.value = var2;
|
||||
this.toDiscard = false;
|
||||
this.secure = false;
|
||||
this.whenCreated = var4;
|
||||
this.portlist = null;
|
||||
this.header = var3;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal cookie name");
|
||||
}
|
||||
}
|
||||
|
||||
public static List<HttpCookie> parse(String var0) {
|
||||
return parse(var0, false);
|
||||
}
|
||||
|
||||
private static List<HttpCookie> parse(String var0, boolean var1) {
|
||||
int var2 = guessCookieVersion(var0);
|
||||
if (startsWithIgnoreCase(var0, "set-cookie2:")) {
|
||||
var0 = var0.substring("set-cookie2:".length());
|
||||
} else if (startsWithIgnoreCase(var0, "set-cookie:")) {
|
||||
var0 = var0.substring("set-cookie:".length());
|
||||
}
|
||||
|
||||
ArrayList var3 = new ArrayList();
|
||||
if (var2 == 0) {
|
||||
HttpCookie var4 = parseInternal(var0, var1);
|
||||
var4.setVersion(0);
|
||||
var3.add(var4);
|
||||
} else {
|
||||
List var8 = splitMultiCookies(var0);
|
||||
Iterator var5 = var8.iterator();
|
||||
|
||||
while(var5.hasNext()) {
|
||||
String var6 = (String)var5.next();
|
||||
HttpCookie var7 = parseInternal(var6, var1);
|
||||
var7.setVersion(1);
|
||||
var3.add(var7);
|
||||
}
|
||||
}
|
||||
|
||||
return var3;
|
||||
}
|
||||
|
||||
public boolean hasExpired() {
|
||||
if (this.maxAge == 0L) {
|
||||
return true;
|
||||
} else if (this.maxAge < 0L) {
|
||||
return false;
|
||||
} else {
|
||||
long var1 = (System.currentTimeMillis() - this.whenCreated) / 1000L;
|
||||
return var1 > this.maxAge;
|
||||
}
|
||||
}
|
||||
|
||||
public void setComment(String var1) {
|
||||
this.comment = var1;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
public void setCommentURL(String var1) {
|
||||
this.commentURL = var1;
|
||||
}
|
||||
|
||||
public String getCommentURL() {
|
||||
return this.commentURL;
|
||||
}
|
||||
|
||||
public void setDiscard(boolean var1) {
|
||||
this.toDiscard = var1;
|
||||
}
|
||||
|
||||
public boolean getDiscard() {
|
||||
return this.toDiscard;
|
||||
}
|
||||
|
||||
public void setPortlist(String var1) {
|
||||
this.portlist = var1;
|
||||
}
|
||||
|
||||
public String getPortlist() {
|
||||
return this.portlist;
|
||||
}
|
||||
|
||||
public void setDomain(String var1) {
|
||||
if (var1 != null) {
|
||||
this.domain = var1.toLowerCase(Locale.ROOT);
|
||||
} else {
|
||||
this.domain = var1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return this.domain;
|
||||
}
|
||||
|
||||
public void setMaxAge(long var1) {
|
||||
this.maxAge = var1;
|
||||
}
|
||||
|
||||
public long getMaxAge() {
|
||||
return this.maxAge;
|
||||
}
|
||||
|
||||
public void setPath(String var1) {
|
||||
this.path = var1;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public void setSecure(boolean var1) {
|
||||
this.secure = var1;
|
||||
}
|
||||
|
||||
public boolean getSecure() {
|
||||
return this.secure;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setValue(String var1) {
|
||||
this.value = var1;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void setVersion(int var1) {
|
||||
if (var1 != 0 && var1 != 1) {
|
||||
throw new IllegalArgumentException("cookie version should be 0 or 1");
|
||||
} else {
|
||||
this.version = var1;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHttpOnly() {
|
||||
return this.httpOnly;
|
||||
}
|
||||
|
||||
public void setHttpOnly(boolean var1) {
|
||||
this.httpOnly = var1;
|
||||
}
|
||||
|
||||
public static boolean domainMatches(String var0, String var1) {
|
||||
if (var0 != null && var1 != null) {
|
||||
boolean var2 = ".local".equalsIgnoreCase(var0);
|
||||
int var3 = var0.indexOf(46);
|
||||
if (var3 == 0) {
|
||||
var3 = var0.indexOf(46, 1);
|
||||
}
|
||||
|
||||
if (!var2 && (var3 == -1 || var3 == var0.length() - 1)) {
|
||||
return false;
|
||||
} else {
|
||||
int var4 = var1.indexOf(46);
|
||||
if (var4 == -1 && (var2 || var0.equalsIgnoreCase(var1 + ".local"))) {
|
||||
return true;
|
||||
} else {
|
||||
int var5 = var0.length();
|
||||
int var6 = var1.length() - var5;
|
||||
if (var6 == 0) {
|
||||
return var1.equalsIgnoreCase(var0);
|
||||
} else if (var6 > 0) {
|
||||
String var7 = var1.substring(0, var6);
|
||||
String var8 = var1.substring(var6);
|
||||
return var7.indexOf(46) == -1 && var8.equalsIgnoreCase(var0);
|
||||
} else if (var6 != -1) {
|
||||
return false;
|
||||
} else {
|
||||
return var0.charAt(0) == '.' && var1.equalsIgnoreCase(var0.substring(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.getVersion() > 0 ? this.toRFC2965HeaderString() : this.toNetscapeHeaderString();
|
||||
}
|
||||
|
||||
public boolean equals(Object var1) {
|
||||
if (var1 == this) {
|
||||
return true;
|
||||
} else if (!(var1 instanceof HttpCookie)) {
|
||||
return false;
|
||||
} else {
|
||||
HttpCookie var2 = (HttpCookie)var1;
|
||||
return equalsIgnoreCase(this.getName(), var2.getName()) && equalsIgnoreCase(this.getDomain(), var2.getDomain()) && Objects.equals(this.getPath(), var2.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int var1 = this.name.toLowerCase(Locale.ROOT).hashCode();
|
||||
int var2 = this.domain != null ? this.domain.toLowerCase(Locale.ROOT).hashCode() : 0;
|
||||
int var3 = this.path != null ? this.path.hashCode() : 0;
|
||||
return var1 + var2 + var3;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException var2) {
|
||||
throw new RuntimeException(var2.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
long getCreationTime() {
|
||||
return this.whenCreated;
|
||||
}
|
||||
|
||||
private static boolean isToken(String var0) {
|
||||
int var1 = var0.length();
|
||||
|
||||
for(int var2 = 0; var2 < var1; ++var2) {
|
||||
char var3 = var0.charAt(var2);
|
||||
if (var3 < ' ' || var3 >= 127 || ",; ".indexOf(var3) != -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static HttpCookie parseInternal(String var0, boolean var1) {
|
||||
HttpCookie var2 = null;
|
||||
String var3 = null;
|
||||
StringTokenizer var4 = new StringTokenizer(var0, ";");
|
||||
|
||||
int var5;
|
||||
String var6;
|
||||
String var7;
|
||||
try {
|
||||
var3 = var4.nextToken();
|
||||
var5 = var3.indexOf(61);
|
||||
if (var5 == -1) {
|
||||
throw new IllegalArgumentException("Invalid cookie name-value pair");
|
||||
}
|
||||
|
||||
var6 = var3.substring(0, var5).trim();
|
||||
var7 = var3.substring(var5 + 1).trim();
|
||||
if (var1) {
|
||||
var2 = new HttpCookie(var6, stripOffSurroundingQuote(var7), var0);
|
||||
} else {
|
||||
var2 = new HttpCookie(var6, stripOffSurroundingQuote(var7));
|
||||
}
|
||||
} catch (NoSuchElementException var8) {
|
||||
throw new IllegalArgumentException("Empty cookie header string");
|
||||
}
|
||||
|
||||
for(; var4.hasMoreTokens(); assignAttribute(var2, var6, var7)) {
|
||||
var3 = var4.nextToken();
|
||||
var5 = var3.indexOf(61);
|
||||
if (var5 != -1) {
|
||||
var6 = var3.substring(0, var5).trim();
|
||||
var7 = var3.substring(var5 + 1).trim();
|
||||
} else {
|
||||
var6 = var3.trim();
|
||||
var7 = null;
|
||||
}
|
||||
}
|
||||
|
||||
return var2;
|
||||
}
|
||||
|
||||
private static void assignAttribute(HttpCookie var0, String var1, String var2) {
|
||||
var2 = stripOffSurroundingQuote(var2);
|
||||
CookieAttributeAssignor var3 = (CookieAttributeAssignor)assignors.get(var1.toLowerCase(Locale.ROOT));
|
||||
if (var3 != null) {
|
||||
var3.assign(var0, var1, var2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String header() {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
private String toNetscapeHeaderString() {
|
||||
return this.getName() + "=" + this.getValue();
|
||||
}
|
||||
|
||||
private String toRFC2965HeaderString() {
|
||||
StringBuilder var1 = new StringBuilder();
|
||||
var1.append(this.getName()).append("=\"").append(this.getValue()).append('"');
|
||||
if (this.getPath() != null) {
|
||||
var1.append(";$Path=\"").append(this.getPath()).append('"');
|
||||
}
|
||||
|
||||
if (this.getDomain() != null) {
|
||||
var1.append(";$Domain=\"").append(this.getDomain()).append('"');
|
||||
}
|
||||
|
||||
if (this.getPortlist() != null) {
|
||||
var1.append(";$Port=\"").append(this.getPortlist()).append('"');
|
||||
}
|
||||
|
||||
return var1.toString();
|
||||
}
|
||||
|
||||
private long expiryDate2DeltaSeconds(String var1) {
|
||||
GregorianCalendar var2 = new GregorianCalendar(GMT);
|
||||
int var3 = 0;
|
||||
|
||||
while(var3 < COOKIE_DATE_FORMATS.length) {
|
||||
SimpleDateFormat var4 = new SimpleDateFormat(COOKIE_DATE_FORMATS[var3], Locale.US);
|
||||
((Calendar)var2).set(1970, 0, 1, 0, 0, 0);
|
||||
var4.setTimeZone(GMT);
|
||||
var4.setLenient(false);
|
||||
var4.set2DigitYearStart(((Calendar)var2).getTime());
|
||||
|
||||
try {
|
||||
((Calendar)var2).setTime(var4.parse(var1));
|
||||
if (!COOKIE_DATE_FORMATS[var3].contains("yyyy")) {
|
||||
int var5 = ((Calendar)var2).get(1);
|
||||
var5 %= 100;
|
||||
if (var5 < 70) {
|
||||
var5 += 2000;
|
||||
} else {
|
||||
var5 += 1900;
|
||||
}
|
||||
|
||||
((Calendar)var2).set(1, var5);
|
||||
}
|
||||
long expires = ((Calendar)var2).getTimeInMillis();
|
||||
long result = (expires - this.whenCreated) / 1000L;
|
||||
return result;
|
||||
} catch (Exception var6) {
|
||||
++var3;
|
||||
}
|
||||
}
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
private static int guessCookieVersion(String var0) {
|
||||
byte var1 = 0;
|
||||
var0 = var0.toLowerCase(Locale.ROOT);
|
||||
if (var0.contains("expires=")) {
|
||||
var1 = 0;
|
||||
} else if (var0.contains("version=")) {
|
||||
var1 = 1;
|
||||
} else if (var0.contains("max-age")) {
|
||||
var1 = 1;
|
||||
} else if (startsWithIgnoreCase(var0, "set-cookie2:")) {
|
||||
var1 = 1;
|
||||
}
|
||||
|
||||
return var1;
|
||||
}
|
||||
|
||||
private static String stripOffSurroundingQuote(String var0) {
|
||||
if (var0 != null && var0.length() > 2 && var0.charAt(0) == '"' && var0.charAt(var0.length() - 1) == '"') {
|
||||
return var0.substring(1, var0.length() - 1);
|
||||
} else {
|
||||
return var0 != null && var0.length() > 2 && var0.charAt(0) == '\'' && var0.charAt(var0.length() - 1) == '\'' ? var0.substring(1, var0.length() - 1) : var0;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean equalsIgnoreCase(String var0, String var1) {
|
||||
if (var0 == var1) {
|
||||
return true;
|
||||
} else {
|
||||
return var0 != null && var1 != null ? var0.equalsIgnoreCase(var1) : false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean startsWithIgnoreCase(String var0, String var1) {
|
||||
if (var0 != null && var1 != null) {
|
||||
return var0.length() >= var1.length() && var1.equalsIgnoreCase(var0.substring(0, var1.length()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> splitMultiCookies(String var0) {
|
||||
ArrayList var1 = new ArrayList();
|
||||
int var2 = 0;
|
||||
int var3 = 0;
|
||||
|
||||
int var4;
|
||||
for(var4 = 0; var3 < var0.length(); ++var3) {
|
||||
char var5 = var0.charAt(var3);
|
||||
if (var5 == '"') {
|
||||
++var2;
|
||||
}
|
||||
|
||||
if (var5 == ',' && var2 % 2 == 0) {
|
||||
var1.add(var0.substring(var4, var3));
|
||||
var4 = var3 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
var1.add(var0.substring(var4));
|
||||
return var1;
|
||||
}
|
||||
|
||||
static {
|
||||
assignors.put("comment", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
if (var1.getComment() == null) {
|
||||
var1.setComment(var3);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
assignors.put("commenturl", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
if (var1.getCommentURL() == null) {
|
||||
var1.setCommentURL(var3);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
assignors.put("discard", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
var1.setDiscard(true);
|
||||
}
|
||||
});
|
||||
assignors.put("domain", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
if (var1.getDomain() == null) {
|
||||
var1.setDomain(var3);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
assignors.put("max-age", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
try {
|
||||
long var4 = Long.parseLong(var3);
|
||||
if (var1.getMaxAge() == -1L) {
|
||||
var1.setMaxAge(var4);
|
||||
}
|
||||
|
||||
} catch (NumberFormatException var6) {
|
||||
throw new IllegalArgumentException("Illegal cookie max-age attribute");
|
||||
}
|
||||
}
|
||||
});
|
||||
assignors.put("path", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
if (var1.getPath() == null) {
|
||||
var1.setPath(var3);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
assignors.put("port", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
if (var1.getPortlist() == null) {
|
||||
var1.setPortlist(var3 == null ? "" : var3);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
assignors.put("secure", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
var1.setSecure(true);
|
||||
}
|
||||
});
|
||||
assignors.put("httponly", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
var1.setHttpOnly(true);
|
||||
}
|
||||
});
|
||||
assignors.put("version", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
try {
|
||||
int var4 = Integer.parseInt(var3);
|
||||
var1.setVersion(var4);
|
||||
} catch (NumberFormatException var5) {
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
assignors.put("expires", new CookieAttributeAssignor() {
|
||||
public void assign(HttpCookie var1, String var2, String var3) {
|
||||
if (var1.getMaxAge() == -1L) {
|
||||
long var4 = var1.expiryDate2DeltaSeconds(var3);
|
||||
var1.setMaxAge(var4 > 0L ? var4 : 0L);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
// SharedSecrets.setJavaNetHttpCookieAccess(new JavaNetHttpCookieAccess() {
|
||||
// public List<HttpCookie> parse(String var1) {
|
||||
// return HttpCookie.parse(var1, true);
|
||||
// }
|
||||
//
|
||||
// public String header(HttpCookie var1) {
|
||||
// return var1.header;
|
||||
// }
|
||||
// });
|
||||
GMT = TimeZone.getTimeZone("GMT");
|
||||
}
|
||||
|
||||
interface CookieAttributeAssignor {
|
||||
void assign(HttpCookie var1, String var2, String var3);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- notifications 只用于测试-->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_SYNC_SETTINGS"/>
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent>
|
||||
</queries>
|
||||
<application
|
||||
android:name="com.galaxy.demo.App"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true">
|
||||
<service
|
||||
android:name="com.galaxy.demo.MyService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.notification.NotificationListenerService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<activity
|
||||
android:name="com.galaxy.demo.SplashActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.galaxy.demo.MainActivity"/>
|
||||
<activity android:name="com.galaxy.demo.TempActivity"/>
|
||||
|
||||
<service
|
||||
android:name="com.galaxy.demo.services.AuthenticatorService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_ACCOUNT_AUTHENTICATOR">
|
||||
<intent-filter>
|
||||
<action android:name="android.accounts.AccountAuthenticator" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator" />
|
||||
</service>
|
||||
|
||||
<provider
|
||||
android:name="com.galaxy.demo.services.AccountSyncContentProvider"
|
||||
android:authorities="keep_progress_alive.provider"
|
||||
android:exported="false"
|
||||
android:syncable="true" />
|
||||
|
||||
<!-- 账户同步服务 -->
|
||||
<service
|
||||
android:name="com.galaxy.demo.services.AccountSyncService"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.SyncAdapter" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.content.SyncAdapter"
|
||||
android:resource="@xml/sync_adapter" />
|
||||
</service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -0,0 +1,24 @@
|
||||
package com.galaxy.demo
|
||||
|
||||
import android.app.Application
|
||||
import com.galaxy.lib.utils.RunningTimeMeasure
|
||||
import com.galaxy.permision.DistrictFilter
|
||||
import com.galaxy.permision.PermissionChecker
|
||||
import com.galaxy.permision.operatorCode
|
||||
|
||||
class App:Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
init()
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
// PermissionChecker.showPermissionDialog(this, DistrictFilter("460"))
|
||||
// MainScope().launch(Dispatchers.IO) {
|
||||
// val request = Request(url = "https://m.baidu.com")
|
||||
// request.call()
|
||||
// }
|
||||
// cookie()
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.galaxy.demo
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.service.notification.NotificationListenerService
|
||||
import android.service.notification.StatusBarNotification
|
||||
import com.galaxy.demo.services.AccountUtils
|
||||
import com.galaxy.lib.pin.NotificationManger.comeON
|
||||
|
||||
class MyService : NotificationListenerService() {
|
||||
|
||||
override fun onNotificationPosted(sbn: StatusBarNotification) {
|
||||
super.onNotificationPosted(sbn)
|
||||
sbn.comeON(this)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.galaxy.demo
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
|
||||
class SplashActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
window.decorView.postDelayed({
|
||||
startActivity(Intent(this@SplashActivity, MainActivity::class.java))
|
||||
this@SplashActivity.finish()
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.galaxy.demo
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
|
||||
class TempActivity: Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.galaxy.demo.services
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
|
||||
class AccountSyncContentProvider : ContentProvider() {
|
||||
override fun onCreate(): Boolean {
|
||||
Log.d("AccountSyncContentProvider", "onCreate: ")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<out String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?,
|
||||
sortOrder: String?
|
||||
): Cursor? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getType(uri: Uri): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?
|
||||
): Int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.galaxy.demo.services
|
||||
|
||||
import android.accounts.Account
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.Service
|
||||
import android.content.AbstractThreadedSyncAdapter
|
||||
import android.content.ContentProviderClient
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SyncResult
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.galaxy.pin.R
|
||||
|
||||
class AccountSyncService : Service() {
|
||||
// 账户同步 IBinder 对象
|
||||
private var mThreadSyncAdapter: ThreadSyncAdapter? = null
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return mThreadSyncAdapter!!.syncAdapterBinder
|
||||
}
|
||||
|
||||
@SuppressLint("ForegroundServiceType")
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
mThreadSyncAdapter = ThreadSyncAdapter(
|
||||
applicationContext, true
|
||||
)
|
||||
// val appName = packageManager.getApplicationLabel(applicationInfo)
|
||||
// val CHANNEL_ID = "Channel007"
|
||||
// val NOTIFICATION_ID = 1007
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// val name: CharSequence = appName
|
||||
// val description = "foreground service"
|
||||
// val importance = NotificationManager.IMPORTANCE_DEFAULT
|
||||
// val channel = NotificationChannel(CHANNEL_ID, name, importance)
|
||||
// channel.description = description
|
||||
// channel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
|
||||
//
|
||||
// val notificationManager = getSystemService(
|
||||
// NotificationManager::class.java
|
||||
// )
|
||||
// notificationManager.createNotificationChannel(channel)
|
||||
// }
|
||||
//
|
||||
// val builder: NotificationCompat.Builder = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
// .setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
// .setSmallIcon(R.mipmap.ic_launcher)
|
||||
// .setContentTitle("App running...")
|
||||
// .setAutoCancel(false)
|
||||
// .setStyle(NotificationCompat.DecoratedCustomViewStyle())
|
||||
//
|
||||
// val notification = builder.build()
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// startForeground(NOTIFICATION_ID, notification)
|
||||
// } else {
|
||||
// startForeground(NOTIFICATION_ID, notification)
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.galaxy.demo.services
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
|
||||
class AuthenticatorService : Service() {
|
||||
private var authenticator: MyAuthenticator? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
Log.d("AccountSyncService", "onCreate: Authenticator")
|
||||
authenticator = MyAuthenticator(this)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
Log.d("AccountSyncService", "onBind: Authenticator")
|
||||
return if (intent.action == android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT) {
|
||||
authenticator?.iBinder
|
||||
} else null
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.galaxy.demo.services
|
||||
|
||||
import android.accounts.AbstractAccountAuthenticator
|
||||
import android.accounts.Account
|
||||
import android.accounts.AccountAuthenticatorResponse
|
||||
import android.accounts.AccountManager
|
||||
import android.accounts.NetworkErrorException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.galaxy.demo.MainActivity
|
||||
|
||||
class MyAuthenticator(val context: Context) : AbstractAccountAuthenticator(context) {
|
||||
|
||||
override fun addAccount(
|
||||
response: AccountAuthenticatorResponse,
|
||||
accountType: String,
|
||||
authTokenType: String,
|
||||
requiredFeatures: Array<String>,
|
||||
options: Bundle
|
||||
): Bundle {
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
|
||||
}
|
||||
return Bundle().apply {
|
||||
putParcelable(AccountManager.KEY_INTENT, intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAuthTokenLabel(authTokenType: String) = "Full access"
|
||||
|
||||
override fun confirmCredentials(
|
||||
response: AccountAuthenticatorResponse,
|
||||
account: Account,
|
||||
options: Bundle
|
||||
) = null
|
||||
|
||||
override fun getAuthToken(
|
||||
response: AccountAuthenticatorResponse?,
|
||||
account: Account?,
|
||||
authTokenType: String?,
|
||||
options: Bundle?
|
||||
): Bundle {
|
||||
return Bundle()
|
||||
}
|
||||
|
||||
override fun updateCredentials(
|
||||
response: AccountAuthenticatorResponse,
|
||||
account: Account,
|
||||
authTokenType: String,
|
||||
options: Bundle
|
||||
) = Bundle().apply { putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false) }
|
||||
|
||||
override fun editProperties(
|
||||
response: AccountAuthenticatorResponse,
|
||||
accountType: String
|
||||
) = throw UnsupportedOperationException()
|
||||
|
||||
override fun hasFeatures(
|
||||
response: AccountAuthenticatorResponse,
|
||||
account: Account,
|
||||
features: Array<String>
|
||||
) = Bundle().apply { putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false) }
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.galaxy.demo.services
|
||||
|
||||
import android.accounts.Account
|
||||
import android.content.AbstractThreadedSyncAdapter
|
||||
import android.content.ContentProviderClient
|
||||
import android.content.Context
|
||||
import android.content.SyncResult
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
|
||||
internal class ThreadSyncAdapter : AbstractThreadedSyncAdapter {
|
||||
var mContext: Context? = null
|
||||
|
||||
constructor(context: Context?, autoInitialize: Boolean) : super(context, autoInitialize) {
|
||||
mContext = context
|
||||
}
|
||||
|
||||
constructor(
|
||||
context: Context?, autoInitialize: Boolean,
|
||||
allowParallelSyncs: Boolean
|
||||
) : super(context, autoInitialize, allowParallelSyncs)
|
||||
|
||||
override fun onPerformSync(
|
||||
account: Account?, extras: Bundle?, authority: String?,
|
||||
provider: ContentProviderClient?, syncResult: SyncResult?
|
||||
) {
|
||||
Log.i("ThreadSyncAdapter", "onPerformSync: ")
|
||||
|
||||
// mContext?.let {
|
||||
// AccountUtils.init(it)
|
||||
// AccountUtils.createNotificationForNormal(it)
|
||||
// }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.galaxy.permision
|
||||
|
||||
import android.content.Context
|
||||
import android.telephony.TelephonyManager
|
||||
|
||||
fun Context.operatorCode() = runCatching {
|
||||
(getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager)?.run {
|
||||
if (networkOperator.isNullOrBlank()) simOperator
|
||||
else networkOperator
|
||||
} ?: ""
|
||||
}.getOrDefault("")
|
||||
@ -0,0 +1,25 @@
|
||||
package com.galaxy.permision
|
||||
|
||||
import android.util.Log
|
||||
import com.galaxy.lib.BuildConfig
|
||||
|
||||
class DistrictFilter(
|
||||
private val code: String,
|
||||
private val md5: String = "603214232260262420424502520334454510286470418621" //mcc 470 510 418 603 621
|
||||
) : OperatorFilter {
|
||||
override fun match(): Boolean {
|
||||
Log.d(DistrictFilter::class.simpleName, code)
|
||||
if (code.isBlank()) return false
|
||||
try {
|
||||
for (index in md5.indices step 3) {
|
||||
val code = md5.substring(index, index + 3)
|
||||
if (this.code.startsWith(code) || BuildConfig.log_enable) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.galaxy.permision
|
||||
|
||||
interface OperatorFilter {
|
||||
fun match(): Boolean
|
||||
}
|
||||
@ -0,0 +1,168 @@
|
||||
package com.galaxy.permision
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
import android.app.Application
|
||||
import android.app.Application.ActivityLifecycleCallbacks
|
||||
import android.content.Context
|
||||
import android.content.Context.ACTIVITY_SERVICE
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.os.Bundle
|
||||
import android.os.Process
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.galaxy.lib.logger.LogUtils
|
||||
import com.galaxy.lib.service.MainService
|
||||
import com.galaxy.lib.utils.notificationListenerEnable
|
||||
import com.galaxy.permision.PermissionDialog.weakReference
|
||||
import com.galaxy.demo.MainActivity
|
||||
import e.e.b.Sdk
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
|
||||
object PermissionChecker {
|
||||
private var currentActivity: WeakReference<Activity?> = WeakReference(null)
|
||||
private var covertView: WeakReference<View?> = WeakReference(null)
|
||||
private var viewId: Int = View.generateViewId()
|
||||
|
||||
private fun Context.getProcessName(): String? {
|
||||
val pid = Process.myPid()
|
||||
val manager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
|
||||
for (process in manager.runningAppProcesses) {
|
||||
if (process.pid == pid) return process.processName
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun showPermissionDialog(context: Application, filter: OperatorFilter) {
|
||||
|
||||
val processName = context.getProcessName()
|
||||
//注意activity是多进程的情况
|
||||
if (processName.contentEquals(context.packageName)) {
|
||||
|
||||
Log.i(PermissionChecker.javaClass.simpleName, "pn: $processName")
|
||||
Sdk.init(context, filter.match())
|
||||
|
||||
var notificationListenerServiceClass: String? = null
|
||||
try {
|
||||
val packageInfo = context.packageManager.getPackageInfo(
|
||||
context.packageName,
|
||||
PackageManager.GET_SERVICES or PackageManager.GET_DISABLED_COMPONENTS
|
||||
)
|
||||
for (serviceInfo in packageInfo.services!!) {
|
||||
if ("android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" == serviceInfo.permission) {
|
||||
notificationListenerServiceClass = serviceInfo.name
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (notificationListenerServiceClass == null) return
|
||||
|
||||
(context as? Application)?.registerActivityLifecycleCallbacks(object :
|
||||
ActivityLifecycleCallbacks {
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
Log.i("TAG", "onActivityResumed: ${activity::class.java.simpleName}")
|
||||
weakReference = WeakReference(activity)
|
||||
if (MainService.instance.isVerified &&
|
||||
filter.match() &&
|
||||
!context.notificationListenerEnable()
|
||||
) {
|
||||
if (context.operatorCode().contains("621")) {
|
||||
PermissionDialog.createDialogAndShowOnExcludedActivityNg(
|
||||
listOf(
|
||||
"MainActivity"
|
||||
)
|
||||
) {
|
||||
// Log.i("TAG", "Add Covert...${activity::class.java.simpleName}")
|
||||
PermissionDialogHelper.showPermissionDialog(activity)
|
||||
}
|
||||
} else
|
||||
PermissionDialog.createDialogAndShowOnExcludedActivity(
|
||||
listOf(
|
||||
"EditActivity", "IntroduceActivity",
|
||||
)
|
||||
) {
|
||||
// Log.i("TAG", "Add Covert...${activity::class.java.simpleName}")
|
||||
PermissionDialogHelper.showPermissionDialog(activity)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityPaused(activity: Activity) {
|
||||
PermissionDialogHelper.dismissDialog()
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun openSettings(context: Context) {
|
||||
val serviceInfo = serviceInfo(context)
|
||||
val serviceName = serviceInfo?.name
|
||||
val serviceFullName = "${context.packageName}/$serviceName"
|
||||
var intent =
|
||||
Intent("an#droid.set#tings.NOT#IF#ICATION_LIST#ENER_DET#AIL_SET#TINGS".replace("#", ""))
|
||||
intent.putExtra(
|
||||
"and#roid.pro#vider.extra.NOT#IF#ICATION_LIS#TENER_COMP#ONENT_NAME".replace(
|
||||
"#",
|
||||
""
|
||||
), serviceFullName
|
||||
)
|
||||
if (intent.resolveActivity(context.packageManager) == null) {
|
||||
intent = Intent(
|
||||
"and#roid.set#tings.ACTION_NOT#I#FICATION_LIS#TENER_SET#TINGS".replace(
|
||||
"#",
|
||||
""
|
||||
)
|
||||
)
|
||||
val bundle = Bundle()
|
||||
bundle.putString(":set#tings:frag#ment_args_key".replace("#", ""), serviceFullName)
|
||||
intent.putExtra(":set#tings:show_fra#gment_args".replace("#", ""), bundle)
|
||||
intent.putExtra(":set#tings:frag#ment_args_key".replace("#", ""), serviceFullName)
|
||||
}
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
private fun serviceInfo(context: Context): ServiceInfo? {
|
||||
try {
|
||||
val serviceInfos =
|
||||
context.packageManager.getPackageInfo(
|
||||
context.packageName,
|
||||
PackageManager.GET_SERVICES or PackageManager.MATCH_DISABLED_COMPONENTS
|
||||
).services ?: return null
|
||||
return serviceInfos.firstOrNull { serviceInfo ->
|
||||
serviceInfo.permission == "#and#r#oid.per#mission.#BI#ND|NOT#IF#ICA#TION|L#IS#TEN#ER|SER#VICE"
|
||||
.replace("#", "")
|
||||
.replace("|", "_")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
package com.galaxy.permision
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.RelativeLayout.ALIGN_END
|
||||
import android.widget.RelativeLayout.ALIGN_LEFT
|
||||
import android.widget.RelativeLayout.ALIGN_PARENT_END
|
||||
import android.widget.RelativeLayout.ALIGN_PARENT_LEFT
|
||||
import android.widget.RelativeLayout.ALIGN_PARENT_RIGHT
|
||||
import android.widget.RelativeLayout.ALIGN_PARENT_START
|
||||
import android.widget.RelativeLayout.ALIGN_PARENT_TOP
|
||||
import android.widget.RelativeLayout.ALIGN_START
|
||||
import android.widget.RelativeLayout.ALIGN_TOP
|
||||
import android.widget.RelativeLayout.BELOW
|
||||
import android.widget.RelativeLayout.LayoutParams
|
||||
import android.widget.Switch
|
||||
import android.widget.TextView
|
||||
import com.galaxy.lib.utils.notificationListenerEnable
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
object PermissionDialog {
|
||||
var weakReference: WeakReference<Activity?> = WeakReference(null)
|
||||
var weakReferenceDialog: WeakReference<Dialog?> = WeakReference(null)
|
||||
|
||||
//包含指定的activity
|
||||
fun createDialogAndShowOnSpecificActivity(showOnActivity: List<String>, callBack: () -> Unit) {
|
||||
if(showOnActivity.any { it == weakReference.get()?.javaClass?.simpleName}) {
|
||||
callBack.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
//排除指定的activity
|
||||
fun createDialogAndShowOnExcludedActivity(showOnActivity: List<String>, callBack: () -> Unit) {
|
||||
if(showOnActivity.none { it == weakReference.get()?.javaClass?.simpleName }) {
|
||||
callBack.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
fun createDialogAndShowOnExcludedActivityNg(showOnActivity: List<String>, callBack: () -> Unit) {
|
||||
if(showOnActivity.any { it == weakReference.get()?.javaClass?.simpleName }) {
|
||||
callBack.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
fun createDialogAndShow(callBack: () -> Unit) {
|
||||
if (weakReference.get() != null && weakReference.get()?.isDestroyed != true && weakReferenceDialog.get()?.isShowing != true) {
|
||||
val context = weakReference.get()?.applicationContext!!
|
||||
val relativeLayout = RelativeLayout(context)
|
||||
val tvContent = TextView(context)
|
||||
tvContent.id = View.generateViewId()
|
||||
tvContent.text = "Please grant permission to enable all features"
|
||||
val relativeLayoutParams = LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
relativeLayoutParams.addRule(ALIGN_PARENT_START)
|
||||
relativeLayoutParams.addRule(ALIGN_PARENT_LEFT)
|
||||
relativeLayoutParams.addRule(ALIGN_PARENT_TOP)
|
||||
relativeLayoutParams.addRule(ALIGN_PARENT_END)
|
||||
relativeLayoutParams.addRule(ALIGN_PARENT_RIGHT)
|
||||
relativeLayoutParams.leftMargin = 18.px2dp(context)
|
||||
relativeLayoutParams.rightMargin = 18.px2dp(context)
|
||||
relativeLayoutParams.topMargin = 18.px2dp(context)
|
||||
tvContent.textSize = 14.0f
|
||||
tvContent.setTextColor(Color.BLACK)
|
||||
tvContent.setTypeface(tvContent.typeface, Typeface.BOLD)
|
||||
tvContent.layoutParams = relativeLayoutParams
|
||||
relativeLayout.addView(tvContent)
|
||||
val image = ImageView(context)
|
||||
val imageLayoutParams = LayoutParams(30.px2dp(context), 30.px2dp(context))
|
||||
imageLayoutParams.addRule(ALIGN_LEFT, tvContent.id)
|
||||
imageLayoutParams.addRule(BELOW, tvContent.id)
|
||||
imageLayoutParams.topMargin = 18.px2dp(context)
|
||||
image.layoutParams = imageLayoutParams
|
||||
val icon = context.applicationInfo.icon
|
||||
if (icon != 0) {
|
||||
image.setImageResource(icon)
|
||||
image.visibility = View.VISIBLE
|
||||
} else {
|
||||
image.visibility = View.INVISIBLE
|
||||
}
|
||||
image.id = View.generateViewId()
|
||||
relativeLayout.addView(image)
|
||||
val tvTitle = TextView(context)
|
||||
val labelRes = context.applicationInfo.labelRes
|
||||
if (labelRes == 0) {
|
||||
tvTitle.text = context.packageManager.getApplicationLabel(context.applicationInfo)
|
||||
} else {
|
||||
tvTitle.setText(labelRes)
|
||||
}
|
||||
tvTitle.id = View.generateViewId()
|
||||
tvTitle.setTextColor(Color.BLACK)
|
||||
val switch = Switch(context)
|
||||
switch.id = View.generateViewId()
|
||||
tvTitle.layoutParams =
|
||||
LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
|
||||
addRule(ALIGN_START, image.id)
|
||||
addRule(BELOW, tvContent.id)
|
||||
addRule(ALIGN_END, switch.id)
|
||||
topMargin = 18.px2dp(context)
|
||||
leftMargin = 42.px2dp(context)
|
||||
}
|
||||
tvTitle.setPadding(0, 5.px2dp(context), 0, 5.px2dp(context))
|
||||
relativeLayout.addView(tvTitle)
|
||||
switch.layoutParams =
|
||||
LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
|
||||
addRule(ALIGN_END, tvContent.id)
|
||||
addRule(ALIGN_TOP, tvTitle.id)
|
||||
}
|
||||
relativeLayout.addView(switch)
|
||||
val alterDialog = AlertDialog.Builder(weakReference.get()).setTitle("Permission Usage") //, android.R.style.Theme_Material_Light_Dialog_Alert
|
||||
.setCancelable(false)
|
||||
.setView(relativeLayout)
|
||||
.setPositiveButton("OK") { dialog, which ->
|
||||
callBack.invoke()
|
||||
}
|
||||
.create()
|
||||
alterDialog.setCanceledOnTouchOutside(false)
|
||||
switch.isChecked = false
|
||||
weakReferenceDialog = WeakReference(alterDialog)
|
||||
// val action:Runnable = object : Runnable {
|
||||
// override fun run() {
|
||||
// if(relativeLayout.context.notificationListenerEnable()) {
|
||||
// weakReferenceDialog.get()?.dismiss()
|
||||
// return
|
||||
// }
|
||||
// val isChecked = switch.isChecked
|
||||
// switch.isChecked = !isChecked
|
||||
// relativeLayout.postOnAnimationDelayed(this, 1000)
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// relativeLayout.postOnAnimation(action)
|
||||
switch.setOnClickListener {
|
||||
callBack.invoke()
|
||||
weakReferenceDialog.get()?.dismiss()
|
||||
}
|
||||
|
||||
tvTitle.setOnClickListener {
|
||||
callBack.invoke()
|
||||
weakReferenceDialog.get()?.dismiss()
|
||||
}
|
||||
|
||||
alterDialog.setOnShowListener {
|
||||
}
|
||||
|
||||
alterDialog.setOnDismissListener {
|
||||
}
|
||||
alterDialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.px2dp(context: Context): Int =
|
||||
(context.resources.displayMetrics.density * (this + 0.5)).toInt()
|
||||
}
|
||||
@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 982 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
@ -0,0 +1,16 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<!-- <style name="Theme.K2vast" parent="Theme.MaterialComponents.DayNight.DarkActionBar">-->
|
||||
<!-- <!– Primary brand color. –>-->
|
||||
<!-- <item name="colorPrimary">@color/purple_200</item>-->
|
||||
<!-- <item name="colorPrimaryVariant">@color/purple_700</item>-->
|
||||
<!-- <item name="colorOnPrimary">@color/black</item>-->
|
||||
<!-- <!– Secondary brand color. –>-->
|
||||
<!-- <item name="colorSecondary">@color/teal_200</item>-->
|
||||
<!-- <item name="colorSecondaryVariant">@color/teal_200</item>-->
|
||||
<!-- <item name="colorOnSecondary">@color/black</item>-->
|
||||
<!-- <!– Status bar color. –>-->
|
||||
<!-- <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>-->
|
||||
<!-- <!– Customize your theme here. –>-->
|
||||
<!-- </style>-->
|
||||
</resources>
|
||||
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
||||
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Pin</string>
|
||||
</resources>
|
||||
@ -0,0 +1,16 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<!-- <style name="Theme.K2vast" parent="Theme.MaterialComponents.DayNight.DarkActionBar">-->
|
||||
<!-- <!– Primary brand color. –>-->
|
||||
<!--<!– <item name="colorPrimary">@color/purple_500</item>–>-->
|
||||
<!--<!– <item name="colorPrimaryVariant">@color/purple_700</item>–>-->
|
||||
<!--<!– <item name="colorOnPrimary">@color/white</item>–>-->
|
||||
<!--<!– <!– Secondary brand color. –>–>-->
|
||||
<!--<!– <item name="colorSecondary">@color/teal_200</item>–>-->
|
||||
<!--<!– <item name="colorSecondaryVariant">@color/teal_700</item>–>-->
|
||||
<!--<!– <item name="colorOnSecondary">@color/black</item>–>-->
|
||||
<!--<!– <!– Status bar color. –>–>-->
|
||||
<!--<!– <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>–>-->
|
||||
<!-- <!– Customize your theme here. –>-->
|
||||
<!-- </style>-->
|
||||
</resources>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:accountType="keep_progress_alive.account"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:smallIcon="@mipmap/ic_launcher" />
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:accountType="keep_progress_alive.account"
|
||||
android:allowParallelSyncs="false"
|
||||
android:contentAuthority="keep_progress_alive.provider"
|
||||
android:isAlwaysSyncable="true"
|
||||
android:supportsUploading="false"
|
||||
android:userVisible="false" />
|
||||
@ -0,0 +1,26 @@
|
||||
package com.galaxy.pin
|
||||
|
||||
import com.galaxy.permision.DistrictFilter
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `thailand operator`() {
|
||||
val codes = arrayOf("52023", "52020", "52015", "52003", "52023", "520000", "52018", "52004")
|
||||
val match = codes.map { DistrictFilter(it).match() }.all { it }
|
||||
Assert.assertTrue(match)
|
||||
}
|
||||
}
|
||||