| @@ -0,0 +1,14 @@ | |||||
| *.iml | |||||
| .gradle | |||||
| /local.properties | |||||
| /.idea/caches | |||||
| /.idea/libraries | |||||
| /.idea/modules.xml | |||||
| /.idea/workspace.xml | |||||
| /.idea/navEditor.xml | |||||
| /.idea/assetWizardSettings.xml | |||||
| .DS_Store | |||||
| /build | |||||
| /captures | |||||
| .externalNativeBuild | |||||
| .cxx | |||||
| @@ -0,0 +1,116 @@ | |||||
| <component name="ProjectCodeStyleConfiguration"> | |||||
| <code_scheme name="Project" version="173"> | |||||
| <codeStyleSettings language="XML"> | |||||
| <indentOptions> | |||||
| <option name="CONTINUATION_INDENT_SIZE" value="4" /> | |||||
| </indentOptions> | |||||
| <arrangement> | |||||
| <rules> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>xmlns:android</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>^$</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| </rule> | |||||
| </section> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>xmlns:.*</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>^$</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| <order>BY_NAME</order> | |||||
| </rule> | |||||
| </section> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>.*:id</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| </rule> | |||||
| </section> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>.*:name</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| </rule> | |||||
| </section> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>name</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>^$</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| </rule> | |||||
| </section> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>style</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>^$</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| </rule> | |||||
| </section> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>.*</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>^$</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| <order>BY_NAME</order> | |||||
| </rule> | |||||
| </section> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>.*</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| <order>ANDROID_ATTRIBUTE_ORDER</order> | |||||
| </rule> | |||||
| </section> | |||||
| <section> | |||||
| <rule> | |||||
| <match> | |||||
| <AND> | |||||
| <NAME>.*</NAME> | |||||
| <XML_ATTRIBUTE /> | |||||
| <XML_NAMESPACE>.*</XML_NAMESPACE> | |||||
| </AND> | |||||
| </match> | |||||
| <order>BY_NAME</order> | |||||
| </rule> | |||||
| </section> | |||||
| </rules> | |||||
| </arrangement> | |||||
| </codeStyleSettings> | |||||
| </code_scheme> | |||||
| </component> | |||||
| @@ -0,0 +1,21 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="GradleMigrationSettings" migrationVersion="1" /> | |||||
| <component name="GradleSettings"> | |||||
| <option name="linkedExternalProjectsSettings"> | |||||
| <GradleProjectSettings> | |||||
| <option name="delegatedBuild" value="false" /> | |||||
| <option name="testRunner" value="PLATFORM" /> | |||||
| <option name="distributionType" value="DEFAULT_WRAPPED" /> | |||||
| <option name="externalProjectPath" value="$PROJECT_DIR$" /> | |||||
| <option name="modules"> | |||||
| <set> | |||||
| <option value="$PROJECT_DIR$" /> | |||||
| <option value="$PROJECT_DIR$/app" /> | |||||
| </set> | |||||
| </option> | |||||
| <option name="resolveModulePerSourceSet" value="false" /> | |||||
| </GradleProjectSettings> | |||||
| </option> | |||||
| </component> | |||||
| </project> | |||||
| @@ -0,0 +1,25 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="RemoteRepositoriesConfiguration"> | |||||
| <remote-repository> | |||||
| <option name="id" value="central" /> | |||||
| <option name="name" value="Maven Central repository" /> | |||||
| <option name="url" value="https://repo1.maven.org/maven2" /> | |||||
| </remote-repository> | |||||
| <remote-repository> | |||||
| <option name="id" value="jboss.community" /> | |||||
| <option name="name" value="JBoss Community repository" /> | |||||
| <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" /> | |||||
| </remote-repository> | |||||
| <remote-repository> | |||||
| <option name="id" value="BintrayJCenter" /> | |||||
| <option name="name" value="BintrayJCenter" /> | |||||
| <option name="url" value="https://jcenter.bintray.com/" /> | |||||
| </remote-repository> | |||||
| <remote-repository> | |||||
| <option name="id" value="Google" /> | |||||
| <option name="name" value="Google" /> | |||||
| <option name="url" value="https://dl.google.com/dl/android/maven2/" /> | |||||
| </remote-repository> | |||||
| </component> | |||||
| </project> | |||||
| @@ -0,0 +1,9 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | |||||
| <output url="file://$PROJECT_DIR$/build/classes" /> | |||||
| </component> | |||||
| <component name="ProjectType"> | |||||
| <option name="id" value="Android" /> | |||||
| </component> | |||||
| </project> | |||||
| @@ -0,0 +1,12 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="RunConfigurationProducerService"> | |||||
| <option name="ignoredProducers"> | |||||
| <set> | |||||
| <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" /> | |||||
| <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" /> | |||||
| <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" /> | |||||
| </set> | |||||
| </option> | |||||
| </component> | |||||
| </project> | |||||
| @@ -0,0 +1 @@ | |||||
| /build | |||||
| @@ -0,0 +1,48 @@ | |||||
| apply plugin: 'com.android.application' | |||||
| android { | |||||
| compileSdkVersion 29 | |||||
| buildToolsVersion "29.0.2" | |||||
| defaultConfig { | |||||
| applicationId "tw.com.altob.goodpk.carin" | |||||
| minSdkVersion 21 | |||||
| targetSdkVersion 29 | |||||
| versionCode 6 | |||||
| versionName "1.5" | |||||
| testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | |||||
| } | |||||
| buildTypes { | |||||
| debug { | |||||
| buildConfigField "String", "API_URL", "\"https://cloudservice.altob.com.tw/LockCarSerivce/api/JumpApi\"" | |||||
| } | |||||
| release { | |||||
| minifyEnabled false | |||||
| proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | |||||
| buildConfigField "String", "API_URL", "\"https://cloudservice.altob.com.tw/LockCarSerivce/api/JumpApi\"" | |||||
| } | |||||
| } | |||||
| } | |||||
| dependencies { | |||||
| implementation fileTree(dir: 'libs', include: ['*.jar']) | |||||
| implementation fileTree(dir: 'libs', include: ['*.aar']) | |||||
| implementation 'androidx.appcompat:appcompat:1.1.0' | |||||
| implementation 'androidx.constraintlayout:constraintlayout:1.1.3' | |||||
| testImplementation 'junit:junit:4.12' | |||||
| androidTestImplementation 'androidx.test.ext:junit:1.1.1' | |||||
| androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' | |||||
| implementation 'com.google.android.material:material:1.0.0' | |||||
| implementation "androidx.loader:loader:1.1.0" | |||||
| //插件 | |||||
| implementation 'com.google.code.gson:gson:2.8.1' | |||||
| implementation 'com.android.support:multidex:1.0.2' | |||||
| implementation 'com.orhanobut:logger:1.8' | |||||
| implementation "com.squareup.okhttp3:okhttp:4.7.2" | |||||
| } | |||||
| @@ -0,0 +1,21 @@ | |||||
| # Add project specific ProGuard rules here. | |||||
| # You can control the set of applied configuration files using the | |||||
| # proguardFiles setting in build.gradle. | |||||
| # | |||||
| # For more details, see | |||||
| # http://developer.android.com/guide/developing/tools/proguard.html | |||||
| # If your project uses WebView with JS, uncomment the following | |||||
| # and specify the fully qualified class name to the JavaScript interface | |||||
| # class: | |||||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | |||||
| # public *; | |||||
| #} | |||||
| # Uncomment this to preserve the line number information for | |||||
| # debugging stack traces. | |||||
| #-keepattributes SourceFile,LineNumberTable | |||||
| # If you keep the line number information, uncomment this to | |||||
| # hide the original source file name. | |||||
| #-renamesourcefileattribute SourceFile | |||||
| @@ -0,0 +1 @@ | |||||
| [{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":6,"versionName":"1.5","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] | |||||
| @@ -0,0 +1,38 @@ | |||||
| package tw.com.altob.goodpk; | |||||
| import android.content.Context; | |||||
| import androidx.test.platform.app.InstrumentationRegistry; | |||||
| import androidx.test.ext.junit.runners.AndroidJUnit4; | |||||
| import org.junit.Test; | |||||
| import org.junit.runner.RunWith; | |||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import java.io.PrintStream; | |||||
| import java.net.URL; | |||||
| import java.net.URLConnection; | |||||
| import tw.com.altob.goodpk.Util.PrefsUtil; | |||||
| import static org.junit.Assert.*; | |||||
| /** | |||||
| * Instrumented test, which will execute on an Android device. | |||||
| * | |||||
| * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |||||
| */ | |||||
| @RunWith(AndroidJUnit4.class) | |||||
| public class ExampleInstrumentedTest { | |||||
| @Test | |||||
| public void useAppContext() { | |||||
| // Context of the app under test. | |||||
| //Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); | |||||
| //assertEquals("tw.com.altob.goodpk", appContext.getPackageName()); | |||||
| //String a = PrefsUtil.md5("ABC1234"); | |||||
| //System.out.println(a); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,71 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| package="tw.com.altob.goodpk"> | |||||
| <!--使用到的權限--> | |||||
| <uses-permission android:name="android.permission.INTERNET" /> | |||||
| <uses-permission android:name="android.permission.CALL_PHONE" /> | |||||
| <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | |||||
| <application | |||||
| android:allowBackup="true" | |||||
| android:icon="@drawable/ic_launcher" | |||||
| android:label="@string/app_name" | |||||
| android:roundIcon="@drawable/ic_launcher" | |||||
| android:supportsRtl="true" | |||||
| android:theme="@style/AppTheme" | |||||
| android:usesCleartextTraffic="true"> | |||||
| <activity android:name=".Activity.MainActivity"> | |||||
| <intent-filter> | |||||
| <action android:name="android.intent.action.MAIN" /> | |||||
| <category android:name="android.intent.category.LAUNCHER" /> | |||||
| </intent-filter> | |||||
| </activity> | |||||
| <activity | |||||
| android:name=".Activity.HomeActivity" | |||||
| android:configChanges="orientation|keyboardHidden|screenSize" | |||||
| android:launchMode="singleTask" | |||||
| android:screenOrientation="portrait"/> | |||||
| <activity | |||||
| android:name=".Activity.CarSecurityActivity" | |||||
| android:configChanges="orientation|keyboardHidden|screenSize" | |||||
| android:launchMode="singleTask" | |||||
| android:screenOrientation="portrait"/> | |||||
| <activity | |||||
| android:name=".Activity.InquireCarActivity" | |||||
| android:configChanges="orientation|keyboardHidden|screenSize" | |||||
| android:windowSoftInputMode="adjustPan|stateHidden" | |||||
| android:launchMode="singleTask" | |||||
| android:screenOrientation="portrait"/> | |||||
| <activity | |||||
| android:name=".Activity.HelpActivity" | |||||
| android:configChanges="orientation|keyboardHidden|screenSize" | |||||
| android:launchMode="singleTask" | |||||
| android:screenOrientation="portrait"/> | |||||
| <activity | |||||
| android:name=".Activity.PaymentActivity" | |||||
| android:configChanges="orientation|keyboardHidden|screenSize" | |||||
| android:launchMode="singleTask" | |||||
| android:screenOrientation="portrait"/> | |||||
| <activity | |||||
| android:name=".Activity.PWActivity" | |||||
| android:configChanges="orientation|keyboardHidden|screenSize" | |||||
| android:launchMode="singleTask" | |||||
| android:screenOrientation="portrait"/> | |||||
| <activity | |||||
| android:name=".Activity.CarLockActivity" | |||||
| android:configChanges="orientation|keyboardHidden|screenSize" | |||||
| android:launchMode="singleTask" | |||||
| android:screenOrientation="portrait"/> | |||||
| </application> | |||||
| </manifest> | |||||
| @@ -0,0 +1,24 @@ | |||||
| package tw.com.altob.goodpk.Activity; | |||||
| import android.os.Bundle; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import com.ga.sdk.activity.BaseActivity; | |||||
| import tw.com.altob.goodpk.Fragment.CarLockFragment; | |||||
| public class CarLockActivity extends BaseActivity { | |||||
| @Override | |||||
| protected void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| this.createToolbarLayout(); | |||||
| this.setTitle("會員防竊首頁"); | |||||
| } | |||||
| @Override | |||||
| protected Fragment newFragment() { | |||||
| return new CarLockFragment(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| package tw.com.altob.goodpk.Activity; | |||||
| import android.os.Bundle; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import com.ga.sdk.activity.BaseActivity; | |||||
| import tw.com.altob.goodpk.Fragment.CarSecurityFragment; | |||||
| public class CarSecurityActivity extends BaseActivity { | |||||
| @Override | |||||
| protected void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| this.createToolbarLayout(); | |||||
| this.setTitle("會員防竊車"); | |||||
| } | |||||
| @Override | |||||
| protected Fragment newFragment() { | |||||
| return new CarSecurityFragment(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| package tw.com.altob.goodpk.Activity; | |||||
| import android.os.Bundle; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import com.ga.sdk.activity.BaseActivity; | |||||
| import tw.com.altob.goodpk.Fragment.HelpFragment; | |||||
| public class HelpActivity extends BaseActivity { | |||||
| @Override | |||||
| protected void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| this.createToolbarLayout(); | |||||
| this.setTitle("緊急協助"); | |||||
| } | |||||
| @Override | |||||
| protected Fragment newFragment() { | |||||
| return new HelpFragment(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| package tw.com.altob.goodpk.Activity; | |||||
| import android.os.Bundle; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import com.ga.sdk.activity.BaseActivity; | |||||
| import tw.com.altob.goodpk.Fragment.HomeFragment; | |||||
| public class HomeActivity extends BaseActivity { | |||||
| @Override | |||||
| protected void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| this.createFrameLayout(); | |||||
| } | |||||
| @Override | |||||
| protected Fragment newFragment() { | |||||
| return new HomeFragment(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| package tw.com.altob.goodpk.Activity; | |||||
| import android.os.Bundle; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import com.ga.sdk.activity.BaseActivity; | |||||
| import tw.com.altob.goodpk.Fragment.InquireCarFragment; | |||||
| public class InquireCarActivity extends BaseActivity { | |||||
| @Override | |||||
| protected void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| this.createToolbarLayout(); | |||||
| this.setTitle("停車位置查詢"); | |||||
| } | |||||
| @Override | |||||
| protected Fragment newFragment() { | |||||
| return new InquireCarFragment(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,49 @@ | |||||
| package tw.com.altob.goodpk.Activity; | |||||
| import androidx.appcompat.app.AppCompatActivity; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import android.content.Intent; | |||||
| import android.os.Bundle; | |||||
| import android.os.Handler; | |||||
| import com.ga.sdk.activity.BaseActivity; | |||||
| import tw.com.altob.goodpk.Fragment.MainFragment; | |||||
| import tw.com.altob.goodpk.R; | |||||
| import tw.com.altob.goodpk.Util.CommonIntent; | |||||
| import tw.com.altob.goodpk.Util.PrefsUtil; | |||||
| public class MainActivity extends BaseActivity { | |||||
| @Override | |||||
| protected void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| //存token(定值) | |||||
| PrefsUtil.setAccountData(MainActivity.this, "9a406a82bd551e6ef8e845f42f788af4"); | |||||
| this.createFrameLayout(); | |||||
| this.nextActivity(); | |||||
| } | |||||
| @Override | |||||
| protected Fragment newFragment() { | |||||
| return new MainFragment(); | |||||
| } | |||||
| private void nextActivity() { | |||||
| Handler handler = new Handler(); | |||||
| handler.postDelayed(new Runnable() { | |||||
| @Override | |||||
| public void run() { | |||||
| Intent intent; | |||||
| intent = CommonIntent.createHomeActivity(MainActivity.this); | |||||
| startActivity(intent); | |||||
| overridePendingTransition(R.anim.right_in,0); | |||||
| finish(); | |||||
| } | |||||
| }, 2000); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| package tw.com.altob.goodpk.Activity; | |||||
| import android.os.Bundle; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import com.ga.sdk.activity.BaseActivity; | |||||
| import tw.com.altob.goodpk.Fragment.PWFragment; | |||||
| public class PWActivity extends BaseActivity { | |||||
| @Override | |||||
| protected void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| this.createToolbarLayout(); | |||||
| this.setTitle("修改密碼"); | |||||
| } | |||||
| @Override | |||||
| protected Fragment newFragment() { | |||||
| return new PWFragment(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| package tw.com.altob.goodpk.Activity; | |||||
| import android.os.Bundle; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import com.ga.sdk.activity.BaseActivity; | |||||
| import tw.com.altob.goodpk.Fragment.PaymentFragment; | |||||
| public class PaymentActivity extends BaseActivity { | |||||
| @Override | |||||
| protected void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| this.createToolbarLayout(); | |||||
| this.setTitle("線上繳費"); | |||||
| } | |||||
| @Override | |||||
| protected Fragment newFragment() { | |||||
| return new PaymentFragment(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,37 @@ | |||||
| package tw.com.altob.goodpk.Api; | |||||
| import android.content.Context; | |||||
| import android.text.TextUtils; | |||||
| import com.ga.sdk.api.AbstractBaseApi; | |||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| import tw.com.altob.goodpk.BuildConfig; | |||||
| import tw.com.altob.goodpk.Util.PrefsUtil; | |||||
| public class BaseApi extends AbstractBaseApi { | |||||
| @Override | |||||
| protected Map<String, String> getHeader() { | |||||
| Map<String, String> headers = null; | |||||
| if (!TextUtils.isEmpty(this.accessToken)) { | |||||
| headers = new HashMap<>(); | |||||
| headers.put("Authorization", "Bearer " + this.accessToken); | |||||
| } | |||||
| return headers; | |||||
| } | |||||
| @Override | |||||
| protected String getAccessToken(Context context) { | |||||
| return PrefsUtil.getAccessToken(context); | |||||
| } | |||||
| @Override | |||||
| protected String toUrl(String path) { | |||||
| return BuildConfig.API_URL + path; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,46 @@ | |||||
| package tw.com.altob.goodpk.Api; | |||||
| import com.ga.sdk.api.Params; | |||||
| import tw.com.altob.goodpk.Util.CryptionUtil; | |||||
| public class GoodPkApi extends BaseApi { | |||||
| //鎖車 | |||||
| private static final String CARSECURITY = "/CARSECURITY?acct=%1$s&pwd=%2$s&status=%3$s&key=%4$s&station=%5$s"; | |||||
| //改密碼 | |||||
| private static final String CHANGEPW = "/change_pwd_40808/%1$s/%2$s/%3$s/%4$s"; | |||||
| //尋車 | |||||
| private static final String CARWHERE = "/CARWHERE?carNo=%1$s"; | |||||
| /*鎖車 | |||||
| 使用者車號 | |||||
| 使用者密碼 | |||||
| 加密後資料 | |||||
| 狀態(0.解鎖 1.鎖車 2.查詢) | |||||
| */ | |||||
| public String getCarSecurity(String acct, String pwd, String status, String key, String station) | |||||
| throws Exception { | |||||
| Params params = new Params(); | |||||
| String Nacct = CryptionUtil.aesEncryptBase64(acct, "Altob"); | |||||
| Nacct = Nacct.replace("\n", ""); | |||||
| return this.doGet( String.format(CARSECURITY, Nacct, pwd, status, key, station), params.getMap()); | |||||
| } | |||||
| public String changePwd(String acct, String pwd, String npwd, String key) | |||||
| throws Exception { | |||||
| Params params = new Params(); | |||||
| return this.doGet( String.format(CHANGEPW, acct, pwd, npwd, key), params.getMap()); | |||||
| } | |||||
| public String getCarWhere(String carNo) | |||||
| throws Exception { | |||||
| Params params = new Params(); | |||||
| return this.doGet( String.format(CARWHERE, CryptionUtil.aesEncryptBase64(carNo, "Altob")), params.getMap()); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,26 @@ | |||||
| package tw.com.altob.goodpk.Bean; | |||||
| import com.google.gson.annotations.SerializedName; | |||||
| import java.io.Serializable; | |||||
| public class CS implements Serializable { | |||||
| @SerializedName("result_code") | |||||
| private String result_code; | |||||
| @SerializedName("result_msg") | |||||
| private String result_msg; | |||||
| public String getResult_code() { | |||||
| return result_code; | |||||
| } | |||||
| public String getResult_msg() { | |||||
| return result_msg; | |||||
| } | |||||
| public void setResult_code(String result_code) { | |||||
| this.result_code = result_code; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,68 @@ | |||||
| package tw.com.altob.goodpk.Bean; | |||||
| import com.google.gson.annotations.SerializedName; | |||||
| import java.io.Serializable; | |||||
| public class CW implements Serializable { | |||||
| @SerializedName("num") | |||||
| private String num; | |||||
| @SerializedName("in_time") | |||||
| private String in_time; | |||||
| @SerializedName("station_no") | |||||
| private String station_no; | |||||
| @SerializedName("station_name") | |||||
| private String station_name; | |||||
| @SerializedName("image_url") | |||||
| private String image_url; | |||||
| @SerializedName("image_url2") | |||||
| private String image_url2; | |||||
| @SerializedName("location_no") | |||||
| private String location_no; | |||||
| @SerializedName("result_code") | |||||
| private String result_code; | |||||
| public String getNum() { | |||||
| return num; | |||||
| } | |||||
| public String getIn_time() { | |||||
| return in_time; | |||||
| } | |||||
| public String getStation_no() { | |||||
| return station_no; | |||||
| } | |||||
| public String getStation_name() { | |||||
| return station_name; | |||||
| } | |||||
| public String getImage_url() { | |||||
| return image_url; | |||||
| } | |||||
| public String getImage_url2() { | |||||
| return image_url2; | |||||
| } | |||||
| public String getLocation_no() { | |||||
| return location_no; | |||||
| } | |||||
| public String getResult_code() { | |||||
| return result_code; | |||||
| } | |||||
| public void setResult_code(String result_code) { | |||||
| this.result_code = result_code; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,204 @@ | |||||
| package tw.com.altob.goodpk.Fragment; | |||||
| import android.content.DialogInterface; | |||||
| import android.content.Intent; | |||||
| import android.os.Bundle; | |||||
| import android.util.Log; | |||||
| import android.view.LayoutInflater; | |||||
| import android.view.View; | |||||
| import android.view.ViewGroup; | |||||
| import android.widget.Button; | |||||
| import android.widget.ImageView; | |||||
| import android.widget.Toast; | |||||
| import androidx.appcompat.app.AlertDialog; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import androidx.loader.content.Loader; | |||||
| import com.ga.sdk.api.ApiResult; | |||||
| import tw.com.altob.goodpk.Bean.CS; | |||||
| import tw.com.altob.goodpk.Loader.ApiLoaderCallback; | |||||
| import tw.com.altob.goodpk.Loader.GetCarSecurityLoader; | |||||
| import tw.com.altob.goodpk.R; | |||||
| import tw.com.altob.goodpk.Util.CommonIntent; | |||||
| import tw.com.altob.goodpk.Util.ExtraKey; | |||||
| import tw.com.altob.goodpk.Util.PrefsUtil; | |||||
| public class CarLockFragment extends Fragment { | |||||
| private String mAcct,mPwd, msg, mkey, mStatus, station; | |||||
| private Button lockBtn, unlockBtn, ChangeBtn; | |||||
| private ImageView carImg, carImg2; | |||||
| @Override | |||||
| public void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| this.mAcct = this.getArguments().getString(ExtraKey.ID); | |||||
| this.mPwd = this.getArguments().getString(ExtraKey.DATA); | |||||
| this.msg = this.getArguments().getString(ExtraKey.OPTION); | |||||
| this.station = this.getArguments().getString(ExtraKey.LOCATION); | |||||
| } | |||||
| @Override | |||||
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |||||
| View contentView = inflater.inflate(R.layout.activity_car_lock, container, false); | |||||
| this.lockBtn = (Button) contentView.findViewById(R.id.lockBtn); | |||||
| this.unlockBtn = (Button) contentView.findViewById(R.id.unlockBtn); | |||||
| //this.ChangeBtn = (Button) contentView.findViewById(R.id.ChangeBtn); | |||||
| this.carImg = (ImageView) contentView.findViewById(R.id.carImg); | |||||
| this.carImg2 = (ImageView) contentView.findViewById(R.id.carImg2); | |||||
| return contentView; | |||||
| } | |||||
| @Override | |||||
| public void onViewCreated(View view, Bundle savedInstanceState) { | |||||
| super.onViewCreated(view, savedInstanceState); | |||||
| if(msg.contains("unlocked")){ | |||||
| carImg2.setVisibility(View.INVISIBLE); | |||||
| carImg.setVisibility(View.VISIBLE); | |||||
| unlockBtn.setEnabled(false); | |||||
| lockBtn.setEnabled(true); | |||||
| }else{ | |||||
| carImg2.setVisibility(View.VISIBLE); | |||||
| carImg.setVisibility(View.INVISIBLE); | |||||
| unlockBtn.setEnabled(true); | |||||
| lockBtn.setEnabled(false); | |||||
| } | |||||
| this.lockBtn.setOnClickListener( this.onLockBtnClickListener); | |||||
| this.unlockBtn.setOnClickListener( this.onUnlockBtnClickListener); | |||||
| //this.ChangeBtn.setOnClickListener( this.onChangeBtnClickListener); | |||||
| } | |||||
| //鎖車 | |||||
| private Button.OnClickListener onLockBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| mStatus = "1"; | |||||
| mkey = PrefsUtil.md5((mAcct + "i" + mPwd + "iii" + mStatus)); | |||||
| ApiLoaderCallback.startApiLoader(getActivity(), setLockLoaderCallback); | |||||
| } | |||||
| }; | |||||
| //解鎖 | |||||
| private Button.OnClickListener onUnlockBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| mStatus = "0"; | |||||
| mkey = PrefsUtil.md5((mAcct + "i" + mPwd + "iii" + mStatus)); | |||||
| ApiLoaderCallback.startApiLoader(getActivity(), setUnLockLoaderCallback); | |||||
| } | |||||
| }; | |||||
| //改密碼 | |||||
| private Button.OnClickListener onChangeBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| //跳修改密碼頁面 | |||||
| Intent intent = new Intent(); | |||||
| intent = CommonIntent.createChangePWActivity(getActivity()); | |||||
| startActivity(intent); | |||||
| getActivity().overridePendingTransition(R.anim.right_in,0); | |||||
| } | |||||
| }; | |||||
| private void showAlert(int titleID, int contentID){ | |||||
| AlertDialog.Builder dialog = new AlertDialog.Builder( getActivity()); | |||||
| dialog.setTitle( getString( titleID)); | |||||
| dialog.setMessage( getString( contentID)); | |||||
| dialog.setNegativeButton( "確認",new DialogInterface.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(DialogInterface arg0, int arg1) { | |||||
| // TODO Auto-generated method stub | |||||
| } | |||||
| }); | |||||
| dialog.show(); | |||||
| } | |||||
| //鎖車 | |||||
| private ApiLoaderCallback<CS> setLockLoaderCallback = new ApiLoaderCallback<CS>() { | |||||
| @Override | |||||
| public Loader<ApiResult<CS>> onCreateLoader(int id, Bundle args) { | |||||
| return new GetCarSecurityLoader( getActivity(), mAcct, mPwd, mStatus, mkey, station); | |||||
| } | |||||
| @Override | |||||
| protected void onStatusOk(CS data) { | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_code()); | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_msg()); | |||||
| if(data.getResult_code().contains("OK")){ | |||||
| Toast.makeText( getContext(), getString(R.string.action_lock), Toast.LENGTH_SHORT).show(); | |||||
| carImg2.setVisibility(View.VISIBLE); | |||||
| carImg.setVisibility(View.INVISIBLE); | |||||
| unlockBtn.setEnabled(true); | |||||
| lockBtn.setEnabled(false); | |||||
| }else{ | |||||
| if(data.getResult_code().contains("-99")){ | |||||
| int title = R.string.action_ca_error; | |||||
| int content = R.string.action_ca_error_lock; | |||||
| showAlert( title, content); | |||||
| }else{ | |||||
| int title = R.string.action_error; | |||||
| int content = R.string.action_error_lock; | |||||
| showAlert( title, content); | |||||
| } | |||||
| } | |||||
| } | |||||
| @Override | |||||
| protected void onPreLoadFinished() { | |||||
| } | |||||
| }; | |||||
| //解鎖 | |||||
| private ApiLoaderCallback<CS> setUnLockLoaderCallback = new ApiLoaderCallback<CS>() { | |||||
| @Override | |||||
| public Loader<ApiResult<CS>> onCreateLoader(int id, Bundle args) { | |||||
| return new GetCarSecurityLoader( getActivity(), mAcct, mPwd, mStatus, mkey, station); | |||||
| } | |||||
| @Override | |||||
| protected void onStatusOk(CS data) { | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_code()); | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_msg()); | |||||
| if(data.getResult_code().contains("OK")){ | |||||
| Toast.makeText( getContext(), getString(R.string.action_unlock), Toast.LENGTH_SHORT).show(); | |||||
| carImg2.setVisibility(View.INVISIBLE); | |||||
| carImg.setVisibility(View.VISIBLE); | |||||
| unlockBtn.setEnabled(false); | |||||
| lockBtn.setEnabled(true); | |||||
| }else{ | |||||
| if(data.getResult_code().contains("-99")){ | |||||
| int title = R.string.action_ca_error; | |||||
| int content = R.string.action_ca_error_lock; | |||||
| showAlert( title, content); | |||||
| }else{ | |||||
| int title = R.string.action_error; | |||||
| int content = R.string.action_error_lock; | |||||
| showAlert( title, content); | |||||
| } | |||||
| } | |||||
| } | |||||
| @Override | |||||
| protected void onPreLoadFinished() { | |||||
| } | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,146 @@ | |||||
| package tw.com.altob.goodpk.Fragment; | |||||
| import android.content.DialogInterface; | |||||
| import android.content.Intent; | |||||
| import android.os.Bundle; | |||||
| import android.util.Log; | |||||
| import android.view.LayoutInflater; | |||||
| import android.view.View; | |||||
| import android.view.ViewGroup; | |||||
| import android.widget.Button; | |||||
| import android.widget.EditText; | |||||
| import android.widget.Toast; | |||||
| import androidx.appcompat.app.AlertDialog; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import androidx.loader.content.Loader; | |||||
| import com.ga.sdk.api.ApiResult; | |||||
| import tw.com.altob.goodpk.Bean.CS; | |||||
| import tw.com.altob.goodpk.Loader.ApiLoaderCallback; | |||||
| import tw.com.altob.goodpk.Loader.GetCarSecurityLoader; | |||||
| import tw.com.altob.goodpk.R; | |||||
| import tw.com.altob.goodpk.Util.CommonIntent; | |||||
| import tw.com.altob.goodpk.Util.ExtraKey; | |||||
| import tw.com.altob.goodpk.Util.PrefsUtil; | |||||
| public class CarSecurityFragment extends Fragment { | |||||
| private Button LoginBtn,ChangeBtn; | |||||
| private EditText AcctText,PwText; | |||||
| private String mAcct, mPwd, mStatus , mkey, station; | |||||
| @Override | |||||
| public void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| station = this.getArguments().getString(ExtraKey.DATA); | |||||
| } | |||||
| @Override | |||||
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |||||
| View contentView = inflater.inflate(R.layout.activity_car_security, container, false); | |||||
| this.LoginBtn = (Button) contentView.findViewById(R.id.LoginBtn); | |||||
| //this.ChangeBtn = (Button) contentView.findViewById(R.id.ChangeBtn); | |||||
| this.AcctText = (EditText) contentView.findViewById(R.id.AcctText); | |||||
| this.PwText = (EditText) contentView.findViewById(R.id.PwText); | |||||
| return contentView; | |||||
| } | |||||
| @Override | |||||
| public void onViewCreated(View view, Bundle savedInstanceState) { | |||||
| super.onViewCreated(view, savedInstanceState); | |||||
| this.LoginBtn.setOnClickListener( this.onLoginBtnClickListener); | |||||
| //this.ChangeBtn.setOnClickListener( this.onChangeBtnClickListener); | |||||
| } | |||||
| private Button.OnClickListener onLoginBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| if(AcctText.getText().length() >0 && PwText.getText().length() >0){ | |||||
| //API | |||||
| mAcct = AcctText.getText().toString(); | |||||
| mPwd = PrefsUtil.md5(PwText.getText().toString()); | |||||
| mStatus = "2"; | |||||
| //Log.d("test", "onClick: " + (mAcct + "i" + mPwd + "iii" + mStatus)); | |||||
| mkey = PrefsUtil.md5((mAcct + "i" + mPwd + "iii" + mStatus)); | |||||
| ApiLoaderCallback.startApiLoader(getActivity(), getCarSecurityLoaderCallback); | |||||
| }else{ | |||||
| int title = R.string.action_error; | |||||
| int content = R.string.action_error_content; | |||||
| showAlert( title, content); | |||||
| } | |||||
| } | |||||
| }; | |||||
| private Button.OnClickListener onChangeBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| //跳修改密碼頁面 | |||||
| Intent intent = new Intent(); | |||||
| intent = CommonIntent.createChangePWActivity(getActivity()); | |||||
| startActivity(intent); | |||||
| getActivity().overridePendingTransition(R.anim.right_in,0); | |||||
| } | |||||
| }; | |||||
| private void showAlert(int titleID, int contentID){ | |||||
| AlertDialog.Builder dialog = new AlertDialog.Builder( getActivity()); | |||||
| dialog.setTitle( getString( titleID)); | |||||
| dialog.setMessage( getString( contentID)); | |||||
| dialog.setNegativeButton( "確認",new DialogInterface.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(DialogInterface arg0, int arg1) { | |||||
| // TODO Auto-generated method stub | |||||
| } | |||||
| }); | |||||
| dialog.show(); | |||||
| } | |||||
| //查詢鎖車狀態 | |||||
| private ApiLoaderCallback<CS> getCarSecurityLoaderCallback = new ApiLoaderCallback<CS>() { | |||||
| @Override | |||||
| public Loader<ApiResult<CS>> onCreateLoader(int id, Bundle args) { | |||||
| return new GetCarSecurityLoader( getActivity(), mAcct, mPwd, mStatus, mkey, station); | |||||
| } | |||||
| @Override | |||||
| protected void onStatusOk(CS data) { | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_code()); | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_msg()); | |||||
| if(data.getResult_code().contains("-99")){ | |||||
| int title = R.string.action_ca_error; | |||||
| int content = R.string.action_ca_error_lock; | |||||
| showAlert( title, content); | |||||
| } | |||||
| if(data.getResult_code().contains("FAIL") || data.getResult_code().contains("fail")){ | |||||
| int title = R.string.action_error; | |||||
| int content = R.string.action_error_car_security; | |||||
| showAlert( title, content); | |||||
| }else{ | |||||
| Toast.makeText( getContext(), getString(R.string.action_login), Toast.LENGTH_SHORT).show(); | |||||
| //登入成功,轉至控制畫面 | |||||
| Intent intent = new Intent(); | |||||
| intent = CommonIntent.createCarLockActivity(getActivity(), mAcct, mPwd, data.getResult_msg(), station); | |||||
| startActivity(intent); | |||||
| getActivity().overridePendingTransition(R.anim.right_in,0); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| protected void onPreLoadFinished() { | |||||
| } | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,89 @@ | |||||
| package tw.com.altob.goodpk.Fragment; | |||||
| import android.content.DialogInterface; | |||||
| import android.content.Intent; | |||||
| import android.net.Uri; | |||||
| import android.os.Bundle; | |||||
| import android.view.LayoutInflater; | |||||
| import android.view.View; | |||||
| import android.view.ViewGroup; | |||||
| import android.widget.Button; | |||||
| import android.widget.Toast; | |||||
| import androidx.annotation.NonNull; | |||||
| import androidx.appcompat.app.AlertDialog; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import tw.com.altob.goodpk.R; | |||||
| import tw.com.altob.goodpk.Util.PermissionCode; | |||||
| import tw.com.altob.goodpk.Util.PermissionUtil; | |||||
| public class HelpFragment extends Fragment { | |||||
| private Button callOutBtn; | |||||
| private String phoneNum = "0229647078"; | |||||
| @Override | |||||
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |||||
| View contentView = inflater.inflate(R.layout.activity_help, container, false); | |||||
| this.callOutBtn = (Button) contentView.findViewById(R.id.callOutBtn); | |||||
| return contentView; | |||||
| } | |||||
| @Override | |||||
| public void onViewCreated(View view, Bundle savedInstanceState) { | |||||
| super.onViewCreated(view, savedInstanceState); | |||||
| this.callOutBtn.setOnClickListener( this.onCallOutBtnClickListener); | |||||
| } | |||||
| private Button.OnClickListener onCallOutBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| int title = R.string.action_import; | |||||
| int content = R.string.action_import_content; | |||||
| showAlert( title, content); | |||||
| } | |||||
| }; | |||||
| //權限回調 | |||||
| @Override | |||||
| public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | |||||
| if (requestCode == PermissionCode.PERMISSION_PHONE) { | |||||
| if (PermissionUtil.checkPhonePermission(this.getActivity())) { | |||||
| callPhone(phoneNum); | |||||
| } else{ | |||||
| Toast.makeText( getContext(),getString(R.string.about_callphone_error), Toast.LENGTH_SHORT).show(); | |||||
| } | |||||
| } | |||||
| } | |||||
| private void callPhone(String phoneNum) { | |||||
| Intent intent = new Intent(Intent.ACTION_CALL); | |||||
| Uri data = Uri.parse("tel:" + phoneNum); | |||||
| intent.setData(data); | |||||
| startActivity(intent); | |||||
| } | |||||
| private void showAlert(int titleID, int contentID){ | |||||
| AlertDialog.Builder dialog = new AlertDialog.Builder( getActivity()); | |||||
| dialog.setTitle( getString( titleID)); | |||||
| dialog.setMessage( getString( contentID)); | |||||
| dialog.setNegativeButton( "確認",new DialogInterface.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(DialogInterface arg0, int arg1) { | |||||
| // TODO Auto-generated method stub | |||||
| PermissionUtil.requestPhonePermissions(HelpFragment.this, PermissionCode.PERMISSION_PHONE); | |||||
| } | |||||
| }); | |||||
| dialog.show(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,196 @@ | |||||
| package tw.com.altob.goodpk.Fragment; | |||||
| import android.content.DialogInterface; | |||||
| import android.content.Intent; | |||||
| import android.os.Bundle; | |||||
| import android.util.Log; | |||||
| import android.view.LayoutInflater; | |||||
| import android.view.View; | |||||
| import android.view.ViewGroup; | |||||
| import android.widget.Button; | |||||
| import android.widget.ImageButton; | |||||
| import android.widget.LinearLayout; | |||||
| import android.widget.TextView; | |||||
| import android.widget.Toast; | |||||
| import androidx.annotation.NonNull; | |||||
| import androidx.appcompat.app.AlertDialog; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import java.util.List; | |||||
| import tw.com.altob.goodpk.R; | |||||
| import tw.com.altob.goodpk.Util.CommonIntent; | |||||
| import tw.com.altob.goodpk.Util.PermissionCode; | |||||
| import tw.com.altob.goodpk.Util.PermissionUtil; | |||||
| import tw.com.altob.goodpk.Util.PrefsUtil; | |||||
| import tw.com.altob.goodpk.Util.ScreenShot; | |||||
| public class HomeFragment extends Fragment { | |||||
| private LinearLayout stationBtn; | |||||
| private TextView stationView; | |||||
| private ImageButton b1, b2, b3, b4; | |||||
| private ScreenShot mScreenShot; | |||||
| private final String[] stationTitle = {"市民廣場","新體","二重公園","金城","澳底"}; | |||||
| private String[] stationCode = {"40808", "12143", "40806", "12117", "12145"}; | |||||
| private String station; | |||||
| @Override | |||||
| public void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| } | |||||
| @Override | |||||
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |||||
| View contentView = inflater.inflate(R.layout.activity_home, container, false); | |||||
| this.b1 = (ImageButton) contentView.findViewById(R.id.imageButton); | |||||
| this.b2 = (ImageButton) contentView.findViewById(R.id.imageButton2); | |||||
| this.b3 = (ImageButton) contentView.findViewById(R.id.imageButton3); | |||||
| this.b4 = (ImageButton) contentView.findViewById(R.id.imageButton4); | |||||
| this.stationBtn = (LinearLayout) contentView.findViewById(R.id.stationBtn); | |||||
| this.stationView = (TextView) contentView.findViewById(R.id.stationView); | |||||
| return contentView; | |||||
| } | |||||
| @Override | |||||
| public void onViewCreated(View view, Bundle savedInstanceState) { | |||||
| super.onViewCreated(view, savedInstanceState); | |||||
| if(PrefsUtil.getFirst( getActivity())){ | |||||
| showAlert(); | |||||
| }else{ | |||||
| PermissionUtil.requestResPermissions(HomeFragment.this, PermissionCode.READ_EXTERNAL_STORAGE); | |||||
| } | |||||
| this.b1.setTag(0); | |||||
| this.b2.setTag(1); | |||||
| this.b3.setTag(2); | |||||
| this.b4.setTag(3); | |||||
| this.b1.setOnClickListener( this.onBtnClickListener); | |||||
| this.b2.setOnClickListener( this.onBtnClickListener); | |||||
| this.b3.setOnClickListener( this.onBtnClickListener); | |||||
| this.b4.setOnClickListener( this.onBtnClickListener); | |||||
| this.stationBtn.setOnClickListener( this.stationLayoutOnClickListener); | |||||
| } | |||||
| private View.OnClickListener stationLayoutOnClickListener = new View.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| showListDialog(); | |||||
| } | |||||
| }; | |||||
| private void showListDialog(){ | |||||
| AlertDialog.Builder dialog_list = new AlertDialog.Builder(getContext()); | |||||
| dialog_list.setTitle( getString(R.string.action_station)); | |||||
| dialog_list.setItems( stationTitle, new DialogInterface.OnClickListener(){ | |||||
| @Override | |||||
| //只要你在onClick處理事件內,使用which參數,就可以知道按下陣列裡的哪一個了 | |||||
| public void onClick(DialogInterface dialog, int which) { | |||||
| //Log.d("test", "onClick: " + which); | |||||
| stationView.setText(getText(R.string.action_station) + " : " + stationTitle[which]); | |||||
| station = stationCode[which]; | |||||
| } | |||||
| }); | |||||
| dialog_list.setNeutralButton( "取消",new DialogInterface.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(DialogInterface arg0, int arg1) { | |||||
| } | |||||
| }); | |||||
| dialog_list.show(); | |||||
| } | |||||
| private Button.OnClickListener onBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| Intent intent = new Intent(); | |||||
| if(station == null){ | |||||
| Toast.makeText(getContext(), "請先選擇場站", Toast.LENGTH_LONG).show(); | |||||
| }else{ | |||||
| switch ((int)v.getTag()){ | |||||
| case 0: | |||||
| intent = CommonIntent.createInquireCarActivity(getActivity()); | |||||
| startActivity(intent); | |||||
| getActivity().overridePendingTransition(R.anim.right_in,0); | |||||
| break; | |||||
| case 1: | |||||
| intent = CommonIntent.createCarSecurityActivity(getActivity(), station); | |||||
| startActivity(intent); | |||||
| getActivity().overridePendingTransition(R.anim.right_in,0); | |||||
| break; | |||||
| case 2: | |||||
| intent = CommonIntent.createHelpActivity(getActivity()); | |||||
| startActivity(intent); | |||||
| getActivity().overridePendingTransition(R.anim.right_in,0); | |||||
| break; | |||||
| case 3: | |||||
| intent = CommonIntent.createPaymentActivity(getActivity()); | |||||
| startActivity(intent); | |||||
| getActivity().overridePendingTransition(R.anim.right_in,0); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| }; | |||||
| private void showAlert(){ | |||||
| AlertDialog.Builder dialog = new AlertDialog.Builder( getActivity()); | |||||
| dialog.setTitle( getString( R.string.main_alert_title)); | |||||
| dialog.setMessage( getString( R.string.main_alert_content)); | |||||
| dialog.setNeutralButton( getString(R.string.main_alert_btn2),new DialogInterface.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(DialogInterface arg0, int arg1) { | |||||
| // TODO Auto-generated method stub | |||||
| getActivity().finish(); | |||||
| } | |||||
| }); | |||||
| dialog.setNegativeButton( getString(R.string.main_alert_btn),new DialogInterface.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(DialogInterface arg0, int arg1) { | |||||
| // TODO Auto-generated method stub | |||||
| PrefsUtil.saveFirst( getActivity()); | |||||
| PermissionUtil.requestResPermissions(HomeFragment.this, PermissionCode.READ_EXTERNAL_STORAGE); | |||||
| } | |||||
| }); | |||||
| dialog.show(); | |||||
| } | |||||
| //權限回調 | |||||
| @Override | |||||
| public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | |||||
| if (requestCode == PermissionCode.READ_EXTERNAL_STORAGE) { | |||||
| if (PermissionUtil.checkResPermission(this.getActivity())) { | |||||
| //啟動截圖監聽 | |||||
| mScreenShot = ScreenShot.getInstance(); | |||||
| handelSystemScreenShot(); | |||||
| } else{ | |||||
| Toast.makeText( getContext(),getString(R.string.about_res_error), Toast.LENGTH_SHORT).show(); | |||||
| } | |||||
| } | |||||
| } | |||||
| private void handelSystemScreenShot() { | |||||
| mScreenShot.register(getActivity(), new ScreenShot.CallbackListener() { | |||||
| @Override | |||||
| public void onShot(String path) { | |||||
| //Log.d("test", " shot : " + path); | |||||
| Toast.makeText( getContext(),getString(R.string.about_res), Toast.LENGTH_SHORT).show(); | |||||
| } | |||||
| }); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,171 @@ | |||||
| package tw.com.altob.goodpk.Fragment; | |||||
| import android.content.DialogInterface; | |||||
| import android.content.Intent; | |||||
| import android.graphics.Bitmap; | |||||
| import android.graphics.BitmapFactory; | |||||
| import android.os.AsyncTask; | |||||
| import android.os.Bundle; | |||||
| import android.util.Log; | |||||
| import android.view.LayoutInflater; | |||||
| import android.view.View; | |||||
| import android.view.ViewGroup; | |||||
| import android.widget.Button; | |||||
| import android.widget.EditText; | |||||
| import android.widget.ImageView; | |||||
| import android.widget.LinearLayout; | |||||
| import android.widget.TextView; | |||||
| import android.widget.Toast; | |||||
| import androidx.appcompat.app.AlertDialog; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import androidx.loader.content.Loader; | |||||
| import com.ga.sdk.api.ApiResult; | |||||
| import java.io.InputStream; | |||||
| import tw.com.altob.goodpk.Bean.CW; | |||||
| import tw.com.altob.goodpk.Loader.ApiLoaderCallback; | |||||
| import tw.com.altob.goodpk.Loader.GetCarWhereLoader; | |||||
| import tw.com.altob.goodpk.R; | |||||
| public class InquireCarFragment extends Fragment { | |||||
| private Button OKBtn; | |||||
| private EditText CarNoText; | |||||
| private TextView stationName,inTime; | |||||
| private ImageView carWhereImg; | |||||
| private LinearLayout stationInfo, stationInfo2; | |||||
| private String carNo; | |||||
| @Override | |||||
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |||||
| View contentView = inflater.inflate(R.layout.activity_inquire_car, container, false); | |||||
| this.OKBtn = (Button) contentView.findViewById(R.id.OKBtn); | |||||
| this.CarNoText = (EditText) contentView.findViewById(R.id.carNoText); | |||||
| this.stationName = (TextView) contentView.findViewById(R.id.stationName); | |||||
| this.inTime = (TextView) contentView.findViewById(R.id.inTime); | |||||
| this.carWhereImg = (ImageView) contentView.findViewById(R.id.carWhereImg); | |||||
| this.stationInfo = (LinearLayout) contentView.findViewById(R.id.stationInfo); | |||||
| this.stationInfo2 = (LinearLayout) contentView.findViewById(R.id.stationIfo2); | |||||
| return contentView; | |||||
| } | |||||
| @Override | |||||
| public void onViewCreated(View view, Bundle savedInstanceState) { | |||||
| super.onViewCreated(view, savedInstanceState); | |||||
| this.OKBtn.setOnClickListener( this.onOKBtnClickListener); | |||||
| } | |||||
| private Button.OnClickListener onOKBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| if(CarNoText.getText().length() >0){ | |||||
| //API | |||||
| carNo = CarNoText.getText().toString(); | |||||
| ApiLoaderCallback.startApiLoader(getActivity(), getCarWhereLoaderCallback); | |||||
| }else{ | |||||
| int title = R.string.action_error; | |||||
| int content = R.string.action_error_content_carno; | |||||
| showAlert( title, content); | |||||
| } | |||||
| } | |||||
| }; | |||||
| private void showAlert(int titleID, int contentID){ | |||||
| AlertDialog.Builder dialog = new AlertDialog.Builder( getActivity()); | |||||
| dialog.setTitle( getString( titleID)); | |||||
| dialog.setMessage( getString( contentID)); | |||||
| dialog.setNegativeButton( "確認",new DialogInterface.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(DialogInterface arg0, int arg1) { | |||||
| // TODO Auto-generated method stub | |||||
| } | |||||
| }); | |||||
| dialog.show(); | |||||
| } | |||||
| //查詢鎖車狀態 | |||||
| private ApiLoaderCallback<CW> getCarWhereLoaderCallback = new ApiLoaderCallback<CW>() { | |||||
| @Override | |||||
| public Loader<ApiResult<CW>> onCreateLoader(int id, Bundle args) { | |||||
| return new GetCarWhereLoader( getActivity(), carNo); | |||||
| } | |||||
| @Override | |||||
| protected void onStatusOk(CW data) { | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_code()); | |||||
| //Log.d("test", "onStatusOk: " + data.getNum()); | |||||
| //Log.d("test", "onStatusOk: " + data.getImage_url()); | |||||
| if(data.getResult_code().contains("OK")){ | |||||
| stationInfo.setVisibility(View.VISIBLE); | |||||
| stationInfo2.setVisibility(View.VISIBLE); | |||||
| carWhereImg.setVisibility(View.VISIBLE); | |||||
| stationName.setText(data.getStation_name()); | |||||
| inTime.setText(data.getIn_time()); | |||||
| if(data.getImage_url2() != null && !data.getImage_url2().isEmpty()){ | |||||
| new DownloadImageTask(carWhereImg).execute(data.getImage_url2()); | |||||
| }else{ | |||||
| new DownloadImageTask(carWhereImg).execute(data.getImage_url()); | |||||
| } | |||||
| }else{ | |||||
| if(data.getResult_code().contains("-99")){ | |||||
| int title = R.string.action_ca_error; | |||||
| int content = R.string.action_ca_error_lock; | |||||
| showAlert( title, content); | |||||
| }else{ | |||||
| int title = R.string.action_error; | |||||
| int content = R.string.action_error_lock; | |||||
| showAlert( title, content); | |||||
| } | |||||
| } | |||||
| } | |||||
| @Override | |||||
| protected void onPreLoadFinished() { | |||||
| } | |||||
| }; | |||||
| private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { | |||||
| ImageView bmImage; | |||||
| public DownloadImageTask(ImageView bmImage) { | |||||
| this.bmImage = bmImage; | |||||
| } | |||||
| protected Bitmap doInBackground(String... urls) { | |||||
| String urldisplay = urls[0]; | |||||
| Bitmap mIcon11 = null; | |||||
| try { | |||||
| InputStream in = new java.net.URL(urldisplay).openStream(); | |||||
| mIcon11 = BitmapFactory.decodeStream(in); | |||||
| } catch (Exception e) { | |||||
| Log.e("Error", e.getMessage()); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| return mIcon11; | |||||
| } | |||||
| protected void onPostExecute(Bitmap result) { | |||||
| bmImage.setImageBitmap(result); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| package tw.com.altob.goodpk.Fragment; | |||||
| import android.os.Bundle; | |||||
| import android.view.LayoutInflater; | |||||
| import android.view.View; | |||||
| import android.view.ViewGroup; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import tw.com.altob.goodpk.R; | |||||
| public class MainFragment extends Fragment { | |||||
| @Override | |||||
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |||||
| return inflater.inflate(R.layout.activity_main, container, false); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,124 @@ | |||||
| package tw.com.altob.goodpk.Fragment; | |||||
| import android.content.DialogInterface; | |||||
| import android.content.Intent; | |||||
| import android.os.Bundle; | |||||
| import android.util.Log; | |||||
| import android.view.LayoutInflater; | |||||
| import android.view.View; | |||||
| import android.view.ViewGroup; | |||||
| import android.widget.Button; | |||||
| import android.widget.EditText; | |||||
| import android.widget.Toast; | |||||
| import androidx.appcompat.app.AlertDialog; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import androidx.loader.content.Loader; | |||||
| import com.ga.sdk.api.ApiResult; | |||||
| import tw.com.altob.goodpk.Bean.CS; | |||||
| import tw.com.altob.goodpk.Loader.ApiLoaderCallback; | |||||
| import tw.com.altob.goodpk.Loader.ChengePWLoader; | |||||
| import tw.com.altob.goodpk.Loader.GetCarSecurityLoader; | |||||
| import tw.com.altob.goodpk.R; | |||||
| import tw.com.altob.goodpk.Util.CommonIntent; | |||||
| import tw.com.altob.goodpk.Util.PrefsUtil; | |||||
| public class PWFragment extends Fragment { | |||||
| private Button DoneBtn; | |||||
| private EditText AcctText,PwText, nPwText; | |||||
| private String mAcct, mPwd, mNPwd , mkey; | |||||
| @Override | |||||
| public void onCreate(Bundle savedInstanceState) { | |||||
| super.onCreate(savedInstanceState); | |||||
| } | |||||
| @Override | |||||
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |||||
| View contentView = inflater.inflate(R.layout.activity_change_pw, container, false); | |||||
| this.DoneBtn = (Button) contentView.findViewById(R.id.DoneBtn); | |||||
| this.AcctText = (EditText) contentView.findViewById(R.id.AcctText); | |||||
| this.PwText = (EditText) contentView.findViewById(R.id.PwText); | |||||
| this.nPwText = (EditText) contentView.findViewById(R.id.nPwText); | |||||
| return contentView; | |||||
| } | |||||
| @Override | |||||
| public void onViewCreated(View view, Bundle savedInstanceState) { | |||||
| super.onViewCreated(view, savedInstanceState); | |||||
| this.DoneBtn.setOnClickListener( this.onLoginBtnClickListener); | |||||
| } | |||||
| private Button.OnClickListener onLoginBtnClickListener = new Button.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(View v) { | |||||
| if(AcctText.getText().length() >0 && PwText.getText().length() >0 && nPwText.getText().length() > 0){ | |||||
| //API | |||||
| mAcct = AcctText.getText().toString(); | |||||
| mPwd = PwText.getText().toString(); | |||||
| mNPwd = nPwText.getText().toString(); | |||||
| //Log.d("test", "onClick: " + (mAcct + "i" + mPwd + "iii" + mNPwd)); | |||||
| mkey = PrefsUtil.md5((mAcct + "i" + mPwd + "iii" + mNPwd)); | |||||
| ApiLoaderCallback.startApiLoader(getActivity(), getChengePWLoaderCallback); | |||||
| }else{ | |||||
| int title = R.string.action_error; | |||||
| int content = R.string.action_error_content2; | |||||
| showAlert( title, content); | |||||
| } | |||||
| } | |||||
| }; | |||||
| private void showAlert(int titleID, int contentID){ | |||||
| AlertDialog.Builder dialog = new AlertDialog.Builder( getActivity()); | |||||
| dialog.setTitle( getString( titleID)); | |||||
| dialog.setMessage( getString( contentID)); | |||||
| dialog.setNegativeButton( "確認",new DialogInterface.OnClickListener() { | |||||
| @Override | |||||
| public void onClick(DialogInterface arg0, int arg1) { | |||||
| // TODO Auto-generated method stub | |||||
| } | |||||
| }); | |||||
| dialog.show(); | |||||
| } | |||||
| //查詢鎖車狀態 | |||||
| private ApiLoaderCallback<CS> getChengePWLoaderCallback = new ApiLoaderCallback<CS>() { | |||||
| @Override | |||||
| public Loader<ApiResult<CS>> onCreateLoader(int id, Bundle args) { | |||||
| return new ChengePWLoader( getActivity(), mAcct, mPwd, mNPwd, mkey); | |||||
| } | |||||
| @Override | |||||
| protected void onStatusOk(CS data) { | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_code()); | |||||
| //Log.d("test", "onStatusOk: " + data.getResult_msg()); | |||||
| if(data.getResult_code().contains("OK")){ | |||||
| Toast.makeText( getContext(), getString(R.string.action_change), Toast.LENGTH_SHORT).show(); | |||||
| getActivity().finish(); | |||||
| }else{ | |||||
| Toast.makeText( getContext(), getString(R.string.action_error_lock), Toast.LENGTH_SHORT).show(); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| protected void onPreLoadFinished() { | |||||
| } | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,39 @@ | |||||
| package tw.com.altob.goodpk.Fragment; | |||||
| import android.os.Build; | |||||
| import android.os.Bundle; | |||||
| import android.view.LayoutInflater; | |||||
| import android.view.View; | |||||
| import android.view.ViewGroup; | |||||
| import android.webkit.WebSettings; | |||||
| import android.webkit.WebView; | |||||
| import android.webkit.WebViewClient; | |||||
| import androidx.fragment.app.Fragment; | |||||
| import tw.com.altob.goodpk.R; | |||||
| public class PaymentFragment extends Fragment { | |||||
| private WebView webView; | |||||
| @Override | |||||
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |||||
| View contentView = inflater.inflate(R.layout.activity_payment, container, false); | |||||
| this.webView = (WebView) contentView.findViewById(R.id.WebView); | |||||
| return contentView; | |||||
| } | |||||
| @Override | |||||
| public void onViewCreated(View view, Bundle savedInstanceState) { | |||||
| super.onViewCreated(view, savedInstanceState); | |||||
| WebSettings webSettings = webView.getSettings(); | |||||
| webSettings.setJavaScriptEnabled(true); | |||||
| if (Build.VERSION.SDK_INT >= 21) { | |||||
| webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); | |||||
| } | |||||
| webView.setWebViewClient(new WebViewClient()); | |||||
| webView.loadUrl( getString(R.string.payment_url)); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| package tw.com.altob.goodpk.Loader; | |||||
| import android.content.Context; | |||||
| import com.ga.sdk.api.ApiResult; | |||||
| import com.ga.sdk.loader.AbstractApiLoaderCallback; | |||||
| import com.orhanobut.logger.Logger; | |||||
| import org.json.JSONException; | |||||
| import tw.com.altob.goodpk.Parser.BaseApiParser; | |||||
| import tw.com.altob.goodpk.Util.PrefsUtil; | |||||
| public abstract class ApiLoaderCallback<T> extends AbstractApiLoaderCallback<T> { | |||||
| @Override | |||||
| protected String toErrorMessage(ApiResult apiResult) { | |||||
| String message; | |||||
| try { | |||||
| message = BaseApiParser.getMessage(apiResult.getError().getBody()); | |||||
| } catch (JSONException e) { | |||||
| int status = apiResult.getError().getStatus(); | |||||
| String reason = apiResult.getError().getReason(); | |||||
| message = "[" + status + "] " + reason; | |||||
| } | |||||
| return message; | |||||
| } | |||||
| @Override | |||||
| protected void handleForbidden(Context context) { | |||||
| try { | |||||
| PrefsUtil.clearData(context); | |||||
| //DBUtil.cleanData(context); | |||||
| } catch (Exception e) { | |||||
| Logger.e(e, e.getMessage()); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,40 @@ | |||||
| package tw.com.altob.goodpk.Loader; | |||||
| import android.content.Context; | |||||
| import androidx.annotation.NonNull; | |||||
| import com.ga.sdk.loader.BaseAsyncTaskLoader; | |||||
| import tw.com.altob.goodpk.Api.GoodPkApi; | |||||
| import tw.com.altob.goodpk.Bean.CS; | |||||
| import tw.com.altob.goodpk.Parser.CarSecurityParser; | |||||
| public class ChengePWLoader extends BaseAsyncTaskLoader<CS> { | |||||
| private String Acct, Pwd, NPwd, Key; | |||||
| private Context mContext; | |||||
| public ChengePWLoader(@NonNull Context context, String mAcct, String mPwd, String mNPwd, String mkey) { | |||||
| super(context); | |||||
| this.mContext = context; | |||||
| this.Acct = mAcct; | |||||
| this.Pwd = mPwd; | |||||
| this.NPwd = mNPwd; | |||||
| this.Key = mkey; | |||||
| } | |||||
| @Override | |||||
| protected String action() throws Exception { | |||||
| GoodPkApi api = new GoodPkApi().withAccessToken(this.mContext); | |||||
| return api.changePwd(this.Acct, this.Pwd, this.NPwd, this.Key); | |||||
| } | |||||
| @Override | |||||
| protected CS parseData(String s) throws Exception { | |||||
| CarSecurityParser parser = new CarSecurityParser(); | |||||
| return parser.toData(s); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,50 @@ | |||||
| package tw.com.altob.goodpk.Loader; | |||||
| import android.content.Context; | |||||
| import android.widget.Switch; | |||||
| import androidx.annotation.NonNull; | |||||
| import com.ga.sdk.loader.BaseAsyncTaskLoader; | |||||
| import tw.com.altob.goodpk.Api.GoodPkApi; | |||||
| import tw.com.altob.goodpk.Bean.CS; | |||||
| import tw.com.altob.goodpk.Bean.CW; | |||||
| import tw.com.altob.goodpk.Parser.CarSecurityParser; | |||||
| public class GetCarSecurityLoader extends BaseAsyncTaskLoader<CS> { | |||||
| private String Acct, Pwd, Status, Key, station; | |||||
| private Context mContext; | |||||
| public GetCarSecurityLoader(@NonNull Context context, String mAcct, String mPwd, String mStatus, String mkey, String station) { | |||||
| super(context); | |||||
| this.mContext = context; | |||||
| this.Acct = mAcct; | |||||
| this.Pwd = mPwd; | |||||
| this.Status = mStatus; | |||||
| this.Key = mkey; | |||||
| this.station = station; | |||||
| } | |||||
| @Override | |||||
| protected String action() throws Exception { | |||||
| GoodPkApi api = new GoodPkApi().withAccessToken(this.mContext); | |||||
| return api.getCarSecurity(this.Acct, this.Pwd, this.Status, this.Key, this.station); | |||||
| } | |||||
| @Override | |||||
| protected CS parseData(String s) throws Exception { | |||||
| CarSecurityParser parser = new CarSecurityParser(); | |||||
| //憑證錯誤 | |||||
| if(s.contains("Certificate pinning failure!")){ | |||||
| CS cs = new CS(); | |||||
| cs.setResult_code("-99"); | |||||
| return cs; | |||||
| }else{ | |||||
| return parser.toData(s); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,44 @@ | |||||
| package tw.com.altob.goodpk.Loader; | |||||
| import android.content.Context; | |||||
| import androidx.annotation.NonNull; | |||||
| import com.ga.sdk.loader.BaseAsyncTaskLoader; | |||||
| import tw.com.altob.goodpk.Api.GoodPkApi; | |||||
| import tw.com.altob.goodpk.Bean.CW; | |||||
| import tw.com.altob.goodpk.Parser.CarWhereParser; | |||||
| public class GetCarWhereLoader extends BaseAsyncTaskLoader<CW> { | |||||
| private String mCarNo; | |||||
| private Context mContext; | |||||
| public GetCarWhereLoader(@NonNull Context context, String carNo) { | |||||
| super(context); | |||||
| this.mContext = context; | |||||
| this.mCarNo = carNo; | |||||
| } | |||||
| @Override | |||||
| protected String action() throws Exception { | |||||
| GoodPkApi api = new GoodPkApi().withAccessToken(this.mContext); | |||||
| return api.getCarWhere(this.mCarNo); | |||||
| } | |||||
| @Override | |||||
| protected CW parseData(String s) throws Exception { | |||||
| CarWhereParser parser = new CarWhereParser(); | |||||
| //憑證錯誤 | |||||
| if(s.contains("Certificate pinning failure!")){ | |||||
| CW cw = new CW(); | |||||
| cw.setResult_code("-99"); | |||||
| return cw; | |||||
| }else{ | |||||
| return parser.toData(s); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,18 @@ | |||||
| package tw.com.altob.goodpk.Parser; | |||||
| import com.ga.sdk.parser.BaseParser; | |||||
| import org.json.JSONException; | |||||
| import org.json.JSONObject; | |||||
| public class BaseApiParser extends BaseParser { | |||||
| public static String getMessage(String jsonString) throws JSONException { | |||||
| return getString(jsonString, "message"); | |||||
| } | |||||
| private static String getString(String jsonString, String key) throws JSONException { | |||||
| JSONObject json = new JSONObject(jsonString); | |||||
| return getString(json, key); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| package tw.com.altob.goodpk.Parser; | |||||
| import com.google.gson.Gson; | |||||
| import com.google.gson.GsonBuilder; | |||||
| public class BaseParser { | |||||
| protected static Gson gson() { | |||||
| return new GsonBuilder().create(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| package tw.com.altob.goodpk.Parser; | |||||
| import tw.com.altob.goodpk.Bean.CS; | |||||
| public class CarSecurityParser extends DataParser<CS> { | |||||
| @Override | |||||
| protected Class<CS> getType() { | |||||
| return CS.class; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| package tw.com.altob.goodpk.Parser; | |||||
| import tw.com.altob.goodpk.Bean.CW; | |||||
| public class CarWhereParser extends DataParser<CW> { | |||||
| @Override | |||||
| protected Class<CW> getType() { | |||||
| return CW.class; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,46 @@ | |||||
| package tw.com.altob.goodpk.Parser; | |||||
| import android.text.TextUtils; | |||||
| import com.google.gson.Gson; | |||||
| import com.google.gson.JsonParseException; | |||||
| import java.lang.reflect.Array; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| public abstract class DataParser<T> extends BaseParser { | |||||
| protected Gson gson; | |||||
| public DataParser() { | |||||
| this.gson = gson(); | |||||
| } | |||||
| public T toData(String json) throws JsonParseException { | |||||
| return this.gson.fromJson(json, getType()); | |||||
| } | |||||
| public List<T> toList(String json) throws JsonParseException { | |||||
| List<T> list = new ArrayList<>(); | |||||
| if (!TextUtils.isEmpty(json)) { | |||||
| Object[] array = (Object[]) Array.newInstance(getType(), 1); | |||||
| array = this.gson.fromJson(json, array.getClass()); | |||||
| for (Object object : array) { | |||||
| @SuppressWarnings("unchecked") | |||||
| T t = (T) object; | |||||
| list.add(t); | |||||
| } | |||||
| } | |||||
| return list; | |||||
| } | |||||
| public String toJson(T t) throws JsonParseException { | |||||
| return this.gson.toJson(t); | |||||
| } | |||||
| protected abstract Class<T> getType(); | |||||
| } | |||||
| @@ -0,0 +1,103 @@ | |||||
| package tw.com.altob.goodpk.Util; | |||||
| import android.content.Context; | |||||
| import android.content.Intent; | |||||
| import androidx.annotation.NonNull; | |||||
| import tw.com.altob.goodpk.Activity.CarLockActivity; | |||||
| import tw.com.altob.goodpk.Activity.CarSecurityActivity; | |||||
| import tw.com.altob.goodpk.Activity.HomeActivity; | |||||
| import tw.com.altob.goodpk.Activity.InquireCarActivity; | |||||
| import tw.com.altob.goodpk.Activity.HelpActivity; | |||||
| import tw.com.altob.goodpk.Activity.PWActivity; | |||||
| import tw.com.altob.goodpk.Activity.PaymentActivity; | |||||
| public class CommonIntent { | |||||
| @NonNull | |||||
| public static Intent createHomeActivity(@NonNull Context context) { | |||||
| return createHomeActivity(context, -1); | |||||
| } | |||||
| @NonNull | |||||
| public static Intent createHomeActivity(@NonNull Context context, int index) { | |||||
| return createHomeActivity(context, index, false); | |||||
| } | |||||
| @NonNull | |||||
| public static Intent createHomeActivity(@NonNull Context context, boolean option) { | |||||
| return createHomeActivity(context, -1, option); | |||||
| } | |||||
| @NonNull | |||||
| private static Intent createHomeActivity(@NonNull Context context, int index, boolean option) { | |||||
| Intent intent = new Intent(context, HomeActivity.class); | |||||
| intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); | |||||
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | |||||
| if (index >= 0) { | |||||
| intent.putExtra(ExtraKey.ID, index); | |||||
| } | |||||
| if (option) { | |||||
| intent.putExtra(ExtraKey.OPTION, true); | |||||
| } | |||||
| return intent; | |||||
| } | |||||
| @NonNull | |||||
| public static Intent createHelpActivity(@NonNull Context context) { | |||||
| Intent intent = new Intent(context, HelpActivity.class); | |||||
| return intent; | |||||
| } | |||||
| @NonNull | |||||
| public static Intent createInquireCarActivity(@NonNull Context context) { | |||||
| Intent intent = new Intent(context, InquireCarActivity.class); | |||||
| return intent; | |||||
| } | |||||
| @NonNull | |||||
| public static Intent createCarSecurityActivity(@NonNull Context context, String station) { | |||||
| Intent intent = new Intent(context, CarSecurityActivity.class); | |||||
| intent.putExtra(ExtraKey.DATA, station); | |||||
| return intent; | |||||
| } | |||||
| @NonNull | |||||
| public static Intent createPaymentActivity(@NonNull Context context) { | |||||
| Intent intent = new Intent(context, PaymentActivity.class); | |||||
| return intent; | |||||
| } | |||||
| @NonNull | |||||
| public static Intent createChangePWActivity(@NonNull Context context) { | |||||
| Intent intent = new Intent(context, PWActivity.class); | |||||
| return intent; | |||||
| } | |||||
| @NonNull | |||||
| public static Intent createCarLockActivity(@NonNull Context context, String acct, String pwd, String msg, String station) { | |||||
| Intent intent = new Intent(context, CarLockActivity.class); | |||||
| intent.putExtra(ExtraKey.ID, acct); | |||||
| intent.putExtra(ExtraKey.DATA, pwd); | |||||
| intent.putExtra(ExtraKey.OPTION, msg); | |||||
| intent.putExtra(ExtraKey.LOCATION, station); | |||||
| return intent; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,149 @@ | |||||
| package tw.com.altob.goodpk.Util; | |||||
| import java.security.MessageDigest; | |||||
| import java.security.NoSuchAlgorithmException; | |||||
| import android.util.Base64; | |||||
| import javax.crypto.Cipher; | |||||
| import javax.crypto.spec.IvParameterSpec; | |||||
| import javax.crypto.spec.SecretKeySpec; | |||||
| public class CryptionUtil { | |||||
| //AES解密 | |||||
| public static String aesDecryptBase64(String carNo, String CryptoKey){ | |||||
| byte[] key = new byte[32]; | |||||
| byte[] iv = new byte[16]; | |||||
| String decKey = ""; | |||||
| String decString = ""; | |||||
| decKey = sha256encrypt(CryptoKey).substring(0, 10); | |||||
| byte[] sha = sha384encrypt(decKey); | |||||
| System.arraycopy(sha, 0, key, 0, 32); | |||||
| System.arraycopy(sha, 32, iv, 0, 16); | |||||
| try { | |||||
| decString = decrypt(carNo, key, iv); | |||||
| } catch (Exception e) { | |||||
| e.printStackTrace(); | |||||
| } | |||||
| return decString; | |||||
| } | |||||
| //AES加密 | |||||
| public static String aesEncryptBase64(String carNo, String CryptoKey){ | |||||
| byte[] key = new byte[32]; | |||||
| byte[] iv = new byte[16]; | |||||
| String encKey = ""; | |||||
| String encString = ""; | |||||
| encKey = sha256encrypt(CryptoKey).substring(0, 10); | |||||
| byte[] sha = sha384encrypt(encKey); | |||||
| System.arraycopy(sha, 0, key, 0, 32); | |||||
| System.arraycopy(sha, 32, iv, 0, 16); | |||||
| try { | |||||
| encString = encrypt(carNo, key, iv); | |||||
| } catch (Exception e) { | |||||
| e.printStackTrace(); | |||||
| } | |||||
| return encString; | |||||
| } | |||||
| //SHA384加密 | |||||
| private static byte[] sha384encrypt(String input){ | |||||
| MessageDigest objSHA = null; | |||||
| try { | |||||
| objSHA = MessageDigest.getInstance("SHA-384"); | |||||
| } catch (NoSuchAlgorithmException e) { | |||||
| e.printStackTrace(); | |||||
| } | |||||
| byte[] bytSHA = objSHA.digest(input.getBytes()); | |||||
| return bytSHA; | |||||
| } | |||||
| //SHA256加密 | |||||
| public static String sha256encrypt(String input){ | |||||
| MessageDigest md = null; | |||||
| String strDes = null; | |||||
| String encName = null; | |||||
| byte[] bt = input.getBytes(); | |||||
| try { | |||||
| encName = "SHA-256"; | |||||
| md = MessageDigest.getInstance(encName); | |||||
| md.update(bt); | |||||
| strDes = bytes2Hex(md.digest()); // to HexString | |||||
| } catch (NoSuchAlgorithmException e) { | |||||
| return null; | |||||
| } | |||||
| return strDes; | |||||
| } | |||||
| private static String bytes2Hex(byte[] bts) { | |||||
| String des = ""; | |||||
| String tmp = null; | |||||
| for (int i = 0; i < bts.length; i++) { | |||||
| tmp = (Integer.toHexString(bts[i] & 0xFF)); | |||||
| if (tmp.length() == 1) { | |||||
| des += "0"; | |||||
| } | |||||
| des += tmp; | |||||
| } | |||||
| return des; | |||||
| } | |||||
| private static String decrypt(String sSrc, byte[] key, byte[] ivs) throws Exception { | |||||
| try { | |||||
| byte[] raw = key; | |||||
| SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); | |||||
| Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); | |||||
| IvParameterSpec iv = new IvParameterSpec(ivs); | |||||
| cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); | |||||
| byte[] encrypted1 = Base64.decode(sSrc, Base64.DEFAULT);// 先用base64解密 | |||||
| byte[] original = cipher.doFinal(encrypted1); | |||||
| String originalString = new String(original, "utf-8"); | |||||
| return originalString; | |||||
| } catch (Exception ex) { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| private static String encrypt(String sSrc, byte[] key, byte[] ivs) throws Exception { | |||||
| SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); | |||||
| Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); | |||||
| IvParameterSpec iv = new IvParameterSpec(ivs); | |||||
| cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); | |||||
| byte[] p = sSrc.getBytes("UTF-8"); | |||||
| byte[] result = cipher.doFinal(p); | |||||
| String encoded = new String(Base64.encode(result, Base64.DEFAULT), "utf-8"); | |||||
| return encoded; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| package tw.com.altob.goodpk.Util; | |||||
| public class ExtraKey { | |||||
| public static final String LOCATION = "location"; | |||||
| public static final String LAT = "lat"; | |||||
| public static final String LON = "lon"; | |||||
| public static final String DATA = "data"; | |||||
| public static final String OPTION = "option"; | |||||
| public static final String TOKEN = "token"; | |||||
| public static final String ID = "id"; | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| package tw.com.altob.goodpk.Util; | |||||
| public class PermissionCode { | |||||
| public static final int PERMISSION_PHONE = 112; | |||||
| public static final int READ_EXTERNAL_STORAGE = 113; | |||||
| } | |||||
| @@ -0,0 +1,53 @@ | |||||
| package tw.com.altob.goodpk.Util; | |||||
| import android.content.Context; | |||||
| import androidx.annotation.NonNull; | |||||
| import androidx.core.content.ContextCompat; | |||||
| import androidx.fragment.app.Fragment; | |||||
| public class PermissionUtil { | |||||
| private static final String[] PHONE_PERMISSIONS = new String[]{"android.permission.CALL_PHONE"}; | |||||
| private static final String[] READ_EXTERNAL_STORAGE = new String[]{"android.permission.READ_EXTERNAL_STORAGE"}; | |||||
| public static boolean checkPhonePermission(@NonNull Context context) { | |||||
| return checkPermissions(context, PHONE_PERMISSIONS); | |||||
| } | |||||
| public static void requestPhonePermissions(@NonNull Fragment fragment, int requestCode) { | |||||
| requestPermissions(fragment, requestCode, PHONE_PERMISSIONS); | |||||
| } | |||||
| protected static void requestPermissions(@NonNull Fragment fragment, int requestCode, String[] permissions) { | |||||
| fragment.requestPermissions(permissions, requestCode); | |||||
| } | |||||
| public static boolean checkResPermission(@NonNull Context context) { | |||||
| return checkPermissions(context, READ_EXTERNAL_STORAGE); | |||||
| } | |||||
| public static void requestResPermissions(@NonNull Fragment fragment, int requestCode) { | |||||
| requestPermissions(fragment, requestCode, READ_EXTERNAL_STORAGE); | |||||
| } | |||||
| protected static boolean checkPermissions(@NonNull Context context, String[]... permissionsArray) { | |||||
| String[][] var2 = permissionsArray; | |||||
| int var3 = permissionsArray.length; | |||||
| for(int var4 = 0; var4 < var3; ++var4) { | |||||
| String[] permissions = var2[var4]; | |||||
| String[] var6 = permissions; | |||||
| int var7 = permissions.length; | |||||
| for(int var8 = 0; var8 < var7; ++var8) { | |||||
| String permission = var6[var8]; | |||||
| if (ContextCompat.checkSelfPermission(context, permission) != 0) { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,113 @@ | |||||
| package tw.com.altob.goodpk.Util; | |||||
| import android.content.Context; | |||||
| import android.content.SharedPreferences; | |||||
| import android.text.TextUtils; | |||||
| import androidx.annotation.NonNull; | |||||
| import com.ga.sdk.util.CryptoUtil; | |||||
| import java.security.MessageDigest; | |||||
| import java.security.NoSuchAlgorithmException; | |||||
| public class PrefsUtil { | |||||
| private static final String PREF_ACCOUNT = "account"; | |||||
| private static final String PREF_MESSAGE = "message"; | |||||
| private static final String PREF_STICKER = "sticker"; | |||||
| private static final String KEY_ACCESS_TOKEN = "accessToken"; | |||||
| private static final String PREF_ADDCARLIST = "AddCar"; | |||||
| private static final String FIRST = "isFirst"; | |||||
| private static final byte[] seed = "Alobot".getBytes(); | |||||
| public static void clearData(@NonNull Context context) { | |||||
| String[] prefs = {PREF_ACCOUNT, PREF_MESSAGE, PREF_STICKER}; | |||||
| for (String pref : prefs) { | |||||
| SharedPreferences preferences = context.getSharedPreferences( | |||||
| pref, Context.MODE_PRIVATE); | |||||
| SharedPreferences.Editor editor = preferences.edit(); | |||||
| editor.clear(); | |||||
| editor.apply(); | |||||
| } | |||||
| } | |||||
| public static String getAccessToken(@NonNull Context context) { | |||||
| SharedPreferences preferences = context.getSharedPreferences( | |||||
| PREF_ACCOUNT, Context.MODE_PRIVATE); | |||||
| String accessToken = preferences.getString(KEY_ACCESS_TOKEN, ""); | |||||
| try { | |||||
| if (!TextUtils.isEmpty(accessToken)) { | |||||
| accessToken = CryptoUtil.decrypt(accessToken, seed); | |||||
| } | |||||
| } catch (Exception e) { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| return accessToken; | |||||
| } | |||||
| public static String md5(String string) { | |||||
| if (TextUtils.isEmpty(string)) { | |||||
| return ""; | |||||
| } | |||||
| MessageDigest md5 = null; | |||||
| try { | |||||
| md5 = MessageDigest.getInstance("MD5"); | |||||
| byte[] bytes = md5.digest(string.getBytes()); | |||||
| String result = ""; | |||||
| for (byte b : bytes) { | |||||
| String temp = Integer.toHexString(b & 0xff); | |||||
| if (temp.length() == 1) { | |||||
| temp = "0" + temp; | |||||
| } | |||||
| result += temp; | |||||
| } | |||||
| return result; | |||||
| } catch (NoSuchAlgorithmException e) { | |||||
| e.printStackTrace(); | |||||
| } | |||||
| return ""; | |||||
| } | |||||
| public static boolean getFirst(@NonNull Context context){ | |||||
| SharedPreferences settings; | |||||
| settings = context.getSharedPreferences(PREF_ADDCARLIST, Context.MODE_PRIVATE); | |||||
| if( settings.getString(FIRST, null) == null){ | |||||
| return true; | |||||
| }else{ | |||||
| return false; | |||||
| } | |||||
| } | |||||
| public static void saveFirst(@NonNull Context context){ | |||||
| SharedPreferences settings; | |||||
| SharedPreferences.Editor editor; | |||||
| settings = context.getSharedPreferences(PREF_ADDCARLIST, Context.MODE_PRIVATE); | |||||
| editor = settings.edit(); | |||||
| editor.putString(FIRST, "true"); | |||||
| editor.commit(); | |||||
| } | |||||
| public static void setAccountData(@NonNull Context context, String token) { | |||||
| SharedPreferences preferences = context.getSharedPreferences( | |||||
| PREF_ACCOUNT, Context.MODE_PRIVATE); | |||||
| SharedPreferences.Editor editor = preferences.edit(); | |||||
| try { | |||||
| editor.putString(KEY_ACCESS_TOKEN, CryptoUtil.encrypt(token, seed)); | |||||
| editor.apply(); | |||||
| } catch (Exception e) { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,194 @@ | |||||
| package tw.com.altob.goodpk.Util; | |||||
| import android.content.ContentResolver; | |||||
| import android.content.Context; | |||||
| import android.database.ContentObserver; | |||||
| import android.database.Cursor; | |||||
| import android.net.Uri; | |||||
| import android.os.Handler; | |||||
| import android.os.HandlerThread; | |||||
| import android.provider.MediaStore; | |||||
| import android.util.Log; | |||||
| public class ScreenShot { | |||||
| private static final String TAG = "ScreenShot"; | |||||
| private static final String[] MEDIA_PROJECTIONS = { | |||||
| MediaStore.Images.ImageColumns.DATA, | |||||
| MediaStore.Images.ImageColumns.DATE_TAKEN, | |||||
| MediaStore.Images.ImageColumns.DATE_ADDED | |||||
| }; | |||||
| /** | |||||
| * 截屏依据中的路径判断关键字 | |||||
| */ | |||||
| private static final String[] KEYWORDS = { | |||||
| "screenshot", "screen_shot", "screen-shot", "screen shot", "screencapture", | |||||
| "screen_capture", "screen-capture", "screen capture", "screencap", "screen_cap", | |||||
| "screen-cap", "screen cap" | |||||
| }; | |||||
| private ContentResolver mContentResolver; | |||||
| private CallbackListener mCallbackListener; | |||||
| private MediaContentObserver mInternalObserver; | |||||
| private MediaContentObserver mExternalObserver; | |||||
| private static ScreenShot mInstance; | |||||
| private ScreenShot() { | |||||
| } | |||||
| /** | |||||
| * 获取 ScreenShot 对象 | |||||
| * | |||||
| * @return ScreenShot对象 | |||||
| */ | |||||
| public static ScreenShot getInstance() { | |||||
| if (mInstance == null) { | |||||
| synchronized (ScreenShot.class) { | |||||
| mInstance = new ScreenShot(); | |||||
| } | |||||
| } | |||||
| return mInstance; | |||||
| } | |||||
| /** | |||||
| * 注册 | |||||
| * | |||||
| * @param context 上下文 | |||||
| * @param callbackListener 回调监听 | |||||
| */ | |||||
| public void register(Context context, CallbackListener callbackListener) { | |||||
| mContentResolver = context.getContentResolver(); | |||||
| mCallbackListener = callbackListener; | |||||
| HandlerThread handlerThread = new HandlerThread(TAG); | |||||
| handlerThread.start(); | |||||
| Handler handler = new Handler(handlerThread.getLooper()); | |||||
| mInternalObserver = new MediaContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, handler); | |||||
| mExternalObserver = new MediaContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, handler); | |||||
| mContentResolver.registerContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, | |||||
| false, mInternalObserver); | |||||
| mContentResolver.registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, | |||||
| false, mExternalObserver); | |||||
| } | |||||
| /** | |||||
| * 注销 | |||||
| */ | |||||
| public void unregister() { | |||||
| if (mContentResolver != null) { | |||||
| mContentResolver.unregisterContentObserver(mInternalObserver); | |||||
| mContentResolver.unregisterContentObserver(mExternalObserver); | |||||
| } | |||||
| } | |||||
| private void handleMediaContentChange(Uri uri) { | |||||
| Cursor cursor = null; | |||||
| try { | |||||
| // 数据改变时,查询数据库中最后加入的一条数据 | |||||
| cursor = mContentResolver.query(uri, MEDIA_PROJECTIONS, null, null, | |||||
| MediaStore.Images.ImageColumns.DATE_ADDED + " desc limit 1"); | |||||
| if (cursor == null) { | |||||
| return; | |||||
| } | |||||
| if (!cursor.moveToFirst()) { | |||||
| return; | |||||
| } | |||||
| int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); | |||||
| int dateAddedIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_ADDED); | |||||
| // 处理获取到的第一行数据 | |||||
| handleMediaRowData(cursor.getString(dataIndex), cursor.getLong(dateAddedIndex)); | |||||
| } catch (Exception e) { | |||||
| e.printStackTrace(); | |||||
| } finally { | |||||
| if (cursor != null && !cursor.isClosed()) { | |||||
| cursor.close(); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 处理监听到的资源 | |||||
| */ | |||||
| private void handleMediaRowData(String path, long dateAdded) { | |||||
| long duration = 0; | |||||
| long step = 100; | |||||
| // 发现个别手机会自己修改截图文件夹的文件,截屏功能会误以为是用户在截屏操作,进行捕获,所以加了一个时间判断 | |||||
| if (!isTimeValid(dateAdded)) { | |||||
| //Log.d(TAG, "图片插入时间大于1秒,不是截屏"); | |||||
| return; | |||||
| } | |||||
| // 设置最大等待时间为500ms,因为魅族的部分手机保存截图有延迟 | |||||
| while (!checkScreenShot(path) && duration <= 500) { | |||||
| try { | |||||
| duration += step; | |||||
| Thread.sleep(step); | |||||
| } catch (Exception e) { | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| if (checkScreenShot(path)) { | |||||
| if (mCallbackListener != null) { | |||||
| mCallbackListener.onShot(path); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 判断时间是否合格,图片插入时间小于1秒才有效 | |||||
| */ | |||||
| private boolean isTimeValid(long dateAdded) { | |||||
| return Math.abs(System.currentTimeMillis() / 1000 - dateAdded) <= 1; | |||||
| } | |||||
| private boolean checkScreenShot(String path) { | |||||
| if (path == null) { | |||||
| return false; | |||||
| } | |||||
| path = path.toLowerCase(); | |||||
| for (String keyword : KEYWORDS) { | |||||
| if (path.contains(keyword)) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| * 媒体内容观察者 | |||||
| */ | |||||
| private class MediaContentObserver extends ContentObserver { | |||||
| private Uri mUri; | |||||
| MediaContentObserver(Uri uri, Handler handler) { | |||||
| super(handler); | |||||
| mUri = uri; | |||||
| } | |||||
| @Override | |||||
| public void onChange(boolean selfChange) { | |||||
| super.onChange(selfChange); | |||||
| //Log.d("ScreenShot", "图片数据库发生变化:" + selfChange); | |||||
| handleMediaContentChange(mUri); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 回调监听器 | |||||
| */ | |||||
| public interface CallbackListener { | |||||
| /** | |||||
| * 截屏 | |||||
| * | |||||
| * @param path 图片路径 | |||||
| */ | |||||
| void onShot(String path); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <translate xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:fromXDelta="100%" | |||||
| android:toXDelta="0" | |||||
| android:duration="300"> | |||||
| </translate> | |||||