| @@ -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> | |||