mirror of
https://github.com/freeedcom/ai-codereviewer.git
synced 2025-06-30 21:04:16 +00:00
add project adins
This commit is contained in:
parent
ad06ac5505
commit
f8f85d679d
5299 changed files with 625430 additions and 0 deletions
1
MSS/BaseProject/Android/branches/BAFMCS_V3/mssbase/.gitignore
vendored
Normal file
1
MSS/BaseProject/Android/branches/BAFMCS_V3/mssbase/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,88 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '29.0.2'
|
||||
android.packageBuildConfig = false
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 30
|
||||
versionCode 2
|
||||
versionName "1.0"
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
debug {
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
dexOptions {
|
||||
javaMaxHeapSize "5g"
|
||||
}
|
||||
testOptions {
|
||||
unitTests.returnDefaultValues = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api fileTree(include: '*.jar', dir: 'libs')
|
||||
api group: 'com.zebra', name: 'android-sdk', version: '1.0'
|
||||
api 'com.google.android.gms:play-services-location:17.1.0'
|
||||
api 'com.google.android.gms:play-services-maps:17.0.0'
|
||||
api 'com.google.firebase:firebase-messaging:20.2.4'
|
||||
api 'com.google.firebase:firebase-core:17.5.0'
|
||||
api 'com.google.firebase:firebase-storage:19.2.0'
|
||||
api 'com.google.firebase:firebase-database:19.4.0'
|
||||
api 'com.google.firebase:firebase-perf:19.1.1'
|
||||
api 'com.google.firebase:firebase-analytics:17.5.0'
|
||||
api 'com.google.firebase:firebase-crashlytics:17.2.1'
|
||||
|
||||
api 'androidx.appcompat:appcompat:1.0.0'
|
||||
// implementation 'com.android.support:support-annotations:28.0.0'
|
||||
api 'com.google.android.material:material:1.0.0'
|
||||
api 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
api 'androidx.cardview:cardview:1.0.0'
|
||||
api 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
api 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
api 'jp.wasabeef:recyclerview-animators:2.2.7'
|
||||
api 'androidx.multidex:multidex:2.0.0'
|
||||
api 'de.greenrobot:eventbus:2.4.0'
|
||||
api 'org.greenrobot:greendao-encryption:2.2.2'
|
||||
api 'net.zetetic:android-database-sqlcipher:4.2.0'
|
||||
api 'de.hdodenhof:circleimageview:2.2.0'
|
||||
|
||||
api files('libs/PaxNeptuneLiteApi_V2.01.00_20171025.jar')
|
||||
api files('libs/PaxNeptuneApi_V1.00.01_20161130.jar')
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
testImplementation 'junit:junit:4.12'
|
||||
api(name:'material-showcase', ext:'aar')
|
||||
// Espresso UI Testing
|
||||
// androidtestImplementation "com.android.support.test.espresso:espresso-core:3.0.2"
|
||||
// androidtestImplementation 'com.android.support.test:rules:1.0.2'
|
||||
// androidtestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
|
||||
testImplementation 'org.mockito:mockito-core:2.7.22'
|
||||
testImplementation 'org.powermock:powermock-core:1.7.0RC2'
|
||||
testImplementation 'org.powermock:powermock-module-junit4:1.7.0RC2'
|
||||
testImplementation 'org.powermock:powermock-api-mockito2:1.7.0RC2'
|
||||
androidTestImplementation 'org.mockito:mockito-android:2.7.22'
|
||||
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
|
||||
|
||||
}
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'kotlin-android-extensions'
|
|
@ -0,0 +1,585 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "814888014770",
|
||||
"firebase_url": "https://aitmss-1fd04.firebaseio.com",
|
||||
"project_id": "aitmss-1fd04",
|
||||
"storage_bucket": "aitmss-1fd04.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:30c443717ea63b1d",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.coll"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-3mnsl7ja8ddiuv5sl5gqfvij9cm973na.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.coll",
|
||||
"certificate_hash": "b07630f358413826df1dceeff13dec3cc7642e36"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-o9drphjl20de1nbt9bd1tbuj08musiis.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.coll",
|
||||
"certificate_hash": "edf00b52879e51d97f85961fd196240bbd316220"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-1crpacj0ttvkjeimakn6qe6pmhu3qeq7.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.coll",
|
||||
"certificate_hash": "e831f754571d0287b1577c64c2f9da80dca8a28d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-lqni1uhtl2omhj2ghl8ennrlpdtgchgi.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.coll",
|
||||
"certificate_hash": "781f237f99355c079785379c9bb39d0c6f036fba"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 2,
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:5c334278ae3d4dbd",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.coll.dev"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:62ea46ede52e350b",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.coll.trial"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:6168d59a3ce39f25",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.svy"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-5f1768ika3hs4ttrek8jmkmf5rahfi1l.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.svy",
|
||||
"certificate_hash": "b07630f358413826df1dceeff13dec3cc7642e36"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-6jbu06k8ntt610ah06be2q8fmf8g49u6.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.svy",
|
||||
"certificate_hash": "edf00b52879e51d97f85961fd196240bbd316220"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-nr69qi0ku9cgok5co187apdpgs0at6ie.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.svy",
|
||||
"certificate_hash": "e831f754571d0287b1577c64c2f9da80dca8a28d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-34mdd9bo2goldi5a5hoeh4iup8nvcdvk.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.svy",
|
||||
"certificate_hash": "781f237f99355c079785379c9bb39d0c6f036fba"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 2,
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:4c9a50b93d56ebef",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.svy.dev"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:48590bba4365ec2d",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.odr"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-itt09df2ovn47an5rearlf1kh8ljp5tt.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.odr",
|
||||
"certificate_hash": "b07630f358413826df1dceeff13dec3cc7642e36"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-09lnve4i7o6ml5436v128stk0jfu5vug.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.odr",
|
||||
"certificate_hash": "edf00b52879e51d97f85961fd196240bbd316220"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-52el593n7dc31cgu431kiqes2qijklie.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.odr",
|
||||
"certificate_hash": "e831f754571d0287b1577c64c2f9da80dca8a28d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-76sm9sf0veuhc96gtiqkdinju9b4al6d.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.odr",
|
||||
"certificate_hash": "781f237f99355c079785379c9bb39d0c6f036fba"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 2,
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:75bff1874bc58298",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.odr.dev"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:41ac49e3a1067b63",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.svy.trial"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:0056a18df222e269",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.odr.trial"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:2ce43e2402f184a7",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.mma"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:81af48a318e62233",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.mma.dev"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:4394bdce086fcfcc",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.mma.trial"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:814888014770:android:7314503471868713",
|
||||
"android_client_info": {
|
||||
"package_name": "com.adins.mss.base"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-51c5dehkiu9o90j7rdq9ke6fvlvaomtc.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.base",
|
||||
"certificate_hash": "781f237f99355c079785379c9bb39d0c6f036fba"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-aqe9bq2rc57suvnangenhpfai77f4j2u.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.adins.mss.base",
|
||||
"certificate_hash": "e831f754571d0287b1577c64c2f9da80dca8a28d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC6ybt31nRknv-l0dzR69vZZGPoSeHkAm8"
|
||||
},
|
||||
{
|
||||
"current_key": "AIzaSyDmV5RbC4xQFgzhTUAQMHUSbtFdl8wduII"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 2,
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "814888014770-qgllsrlpktvi162r6uqae4on3qtg0ap2.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
691
MSS/BaseProject/Android/branches/BAFMCS_V3/mssbase/proguard-rules.pro
vendored
Normal file
691
MSS/BaseProject/Android/branches/BAFMCS_V3/mssbase/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,691 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\Users\gigin.ginanjar\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# 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 *;
|
||||
#}
|
||||
#-injars bin/classes
|
||||
#-injars libs
|
||||
##-outjars bin/classes-processed.jar
|
||||
##-libraryjars "C:\Users\gigin.ginanjar\AppData\Local\Android\sdk/platforms\android-23/android.jar"
|
||||
#
|
||||
-dontpreverify
|
||||
#-repackageclasses ''
|
||||
-allowaccessmodification
|
||||
-optimizations !code/simplification/arithmetic,!field
|
||||
-keepattributes Signature
|
||||
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends androidx.fragment.app.Fragment
|
||||
-keep public class * extends androidx.fragment.app.FragmentActivity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
|
||||
-keepclassmembers class * extends android.content.Context {
|
||||
public void *(android.view.View);
|
||||
public void *(android.view.NewMenuItem);
|
||||
}
|
||||
|
||||
-keepclassmembers class * implements android.os.Parcelable {
|
||||
static ** CREATOR;
|
||||
}
|
||||
|
||||
#-keepclassmembers class **.R$* {
|
||||
# public static <fields>;
|
||||
#}
|
||||
|
||||
-keep class com.adins.mss.base.R$* {
|
||||
public static <fields>;
|
||||
}
|
||||
|
||||
-keepclassmembers class ** {
|
||||
public static *** parse(***);
|
||||
}
|
||||
-keepclassmembers class ** {
|
||||
public static <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.logger.Logger{
|
||||
public <methods>;
|
||||
}
|
||||
|
||||
### greenDAO 3
|
||||
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
|
||||
public static java.lang.String TABLENAME;
|
||||
}
|
||||
-keep class **$Properties
|
||||
|
||||
# If you do not use SQLCipher:
|
||||
-dontwarn org.greenrobot.greendao.database.**
|
||||
# If you do not use RxJava:
|
||||
-dontwarn rx.**
|
||||
|
||||
### greenDAO 2
|
||||
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
|
||||
public static java.lang.String TABLENAME;
|
||||
}
|
||||
-keep class **$Properties
|
||||
|
||||
-keepclassmembers class * {
|
||||
@android.webkit.JavascriptInterface <methods>;
|
||||
}
|
||||
|
||||
-keepattributes InnerClasses
|
||||
|
||||
-dontwarn okio.**
|
||||
-dontwarn com.androidquery.**
|
||||
-dontwarn org.apache.commons.jexl2.**
|
||||
-dontwarn com.fasterxml.uuid.**
|
||||
-dontwarn org.bouncycastle.**
|
||||
-dontwarn java.lang.**
|
||||
-dontwarn fr.castorflex.android.smoothprogressbar.**
|
||||
-dontwarn lib.gegemobile.**
|
||||
-dontwarn uk.co.senab.actionbarpulltorefresh.library.**
|
||||
-dontwarn zj.com.**
|
||||
-dontwarn org.apache.**
|
||||
-dontwarn com.pax.**
|
||||
-dontwarn android.databinding.**
|
||||
|
||||
-keep class android.databinding.** { *; }
|
||||
-keep class androidx.databinding.** { *; }
|
||||
-keep class * extends androidx.databinding.DataBinderMapper { *; }
|
||||
-keep class com.adins.mss.base.databinding.** { *; }
|
||||
|
||||
|
||||
#Keep classes that are referenced on the AndroidManifest
|
||||
-keep public class * extends androidx.appcompat.app.AppCompatActivity
|
||||
-keep public class * extends com.adins.mss.base.MssFragmentActivity
|
||||
-keep public class * extends androidx.fragment.app.Fragment
|
||||
-keep public class * extends androidx.fragment.app.FragmentActivity
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keepclassmembers class * extends androidx.fragment.app.Fragment{
|
||||
public void *(android.view.View);
|
||||
}
|
||||
-keep class com.androidquery.AQuery {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep class android.** { *; }
|
||||
-keep class com.google.** { *; }
|
||||
|
||||
-keep class com.google.gson.JsonSyntaxException {public protected static *; }
|
||||
|
||||
-keep class org.acra.sender.HttpSender {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class androidx.fragment.app.FragmentManager{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep class org.acra.annotation.** {*; }
|
||||
-keep class org.acra.ReportField {*; }
|
||||
-keep class org.acra.ReportingInteractionMode {*; }
|
||||
-keep class org.acra.annotation.ReportsCrashes {public protected static *; }
|
||||
-keep class org.acra.ErrorReporter {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class java.lang.String {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep public enum org.acra.sender.HttpSender.Type$** {
|
||||
*;
|
||||
}
|
||||
-keep public enum org.acra.sender.HttpSender.Method$** {
|
||||
*;
|
||||
}
|
||||
|
||||
-keepclassmembers,allowoptimization enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class org.acra.annotation.** {*; }
|
||||
-keep class org.acra.ReportField {*; }
|
||||
-keep class org.acra.ReportingInteractionMode {*; }
|
||||
-keep class org.acra.annotation.ReportsCrashes {public protected static *; }
|
||||
-keep class org.acra.ErrorReporter {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class java.lang.String {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keepclassmembers,allowoptimization enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
#keep class for mss
|
||||
#-keep class com.adins.foundation.**
|
||||
-keep class com.adins.mss.dao.** {*;}
|
||||
-keep class com.adins.mss.constant.** {*;}
|
||||
-keep class com.adins.mss.base.crashlytics.** {*;}
|
||||
-keep class com.adins.mss.foundation.** {*;}
|
||||
-keep class com.adins.mss.foundation.db.dataaccess.** {*;}
|
||||
-keep class com.adins.mss.base.login.DefaultLoginModel
|
||||
-keep class com.squareup.okhttp.** {*;}
|
||||
-keep class com.androidquery.** {*;}
|
||||
-keep class android.view.animation.** {*;}
|
||||
-keep class com.adins.mss.base.todolist.todayplanrepository.** {*;}
|
||||
|
||||
#Nendi: 17.12.2020
|
||||
-keep class com.adins.mss.foundation.security.storepreferences.ObscuredSharedPreferences {*;}
|
||||
|
||||
-keepclasseswithmembernames class com.adins.mss.base.commons.SecondHelper
|
||||
|
||||
-keep public class com.gadberry.** {*;}
|
||||
|
||||
-keep public class * extends android.view.View {
|
||||
public <init>(android.content.Context);
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
public void set*(...);
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.util.Utility{
|
||||
public <methods>;
|
||||
}
|
||||
|
||||
-keep class com.adins.mss.base.dynamictheme.DynamicTheme{
|
||||
public <methods>;
|
||||
}
|
||||
|
||||
-keep class com.soundcloud.android.crop.Crop{
|
||||
public <methods>;
|
||||
public public <fields>;
|
||||
}
|
||||
|
||||
-keep class com.adins.mss.base.dynamictheme.ThemeLoader{
|
||||
public <methods>;
|
||||
public public <fields>;
|
||||
}
|
||||
|
||||
-keep public interface com.adins.mss.base.dynamictheme.ThemeLoader$ColorSetLoaderCallback {*;}
|
||||
|
||||
-keep class com.adins.mss.base.dynamictheme.ThemeUtility{
|
||||
public <methods>;
|
||||
}
|
||||
-keep public class com.adins.mss.base.util.EventBusHelper{
|
||||
public <methods>;
|
||||
}
|
||||
-keep public class com.adins.mss.base.util.LocaleHelper{
|
||||
public <methods>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.checkin.CheckInManager{
|
||||
public <methods>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.errorhandler.ErrorMessageHandler{
|
||||
public <methods>;
|
||||
}
|
||||
-keep public class com.adins.mss.base.errorhandler.IShowError{
|
||||
public <methods>;
|
||||
}
|
||||
|
||||
-keep class net.sqlcipher.** {
|
||||
*;
|
||||
}
|
||||
|
||||
-keep class com.zebra.** { *; }
|
||||
-keep interface com.zebra.** { *; }
|
||||
-keep class com.fasterxml.** { *; }
|
||||
-keep interface com.fasterxml.** { *; }
|
||||
-keep interface com.adins.libs.** { *; }
|
||||
-keep class uk.co.deanwild.materialshowcaseview.** { *; }
|
||||
-keep interface uk.co.deanwild.materialshowcaseview.** { *; }
|
||||
|
||||
-keep class com.adins.mss.base.commons.CommonImpl{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.tasklog.TaskLogImpl{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.commons.ViewImpl{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.commons.TaskListener{
|
||||
public <methods>;
|
||||
}
|
||||
|
||||
-keep class com.adins.mss.base.depositreport.TaskLogHelper{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.form.questions.viewholder.ImageQuestionViewHolder{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.timeline.Constants{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.TaskDBean{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class org.acra.ACRAConfiguration{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.services.ForegroundServiceNotification{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.services.SurveyAssignmentThread{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.commons.BackupManager{
|
||||
public <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.mainmenu.NewMenuItem{
|
||||
public <methods>;
|
||||
}
|
||||
|
||||
-keep class com.adins.mss.base.NewMainActivity{
|
||||
public static <fields>;
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep class com.adins.mss.base.AppContext {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class org.acra.annotation.ReportsCrashes {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class org.acra.ReportField {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class org.acra.ReportingInteractionMode {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.GlobalData {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.util.GsonHelper {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep class com.adins.mss.base.util.ExcludeFromGson{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
|
||||
}
|
||||
|
||||
-keep class com.adins.mss.foundation.dialog.NiftyDialogBuilder {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.http.HttpConnectionResult {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.http.HttpCryptedConnection {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep class org.acra.ACRA {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.http.KeyValue {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.http.MssResponseType {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class androidx.fragment.app.Fragment {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.dao.TaskH {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.timeline.MapsViewer {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.dialog.DialogManager {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.formatter.Tool {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.image.Utils {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.mainmenu.MainMenuActivity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class androidx.fragment.app.FragmentActivity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class androidx.fragment.app.FragmentTransaction {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.JsonResponseSubmitTask {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.mikepenz.aboutlibraries.entity.Library {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.CustomerFragment {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.SurveyHeaderBean {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.tasklog.TaskLogArrayAdapter {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.timeline.TimelineManager {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todolist.ToDoList {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todolist.form.JsonResponseTaskList {
|
||||
public protected <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.dao.Scheme {
|
||||
public protected <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.dao.User {
|
||||
public protected <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.db.dataaccess.SchemeDataAccess {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.db.dataaccess.TaskHDataAccess {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.db.dataaccess.TimelineDataAccess {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.db.dataaccess.TimelineTypeDataAccess {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.http.MssRequestType {
|
||||
public protected <methods>;
|
||||
}
|
||||
-keep class com.mikepenz.aboutlibraries.entity.License {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.about.activity.AboutActivity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.login.DefaultLoginModel {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.LoginActivity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class androidx.core.app.NotificationCompat {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.JsonRequestTaskD {
|
||||
public protected <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.JsonResponseTaskD {
|
||||
public protected <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.timeline.activity.Timeline_Activity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.dao.TaskD {
|
||||
public protected <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.db.dataaccess.GeneralParameterDataAccess {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.db.dataaccess.TaskDDataAccess {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.notification.Notification {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.ChangePasswordFragment {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.mainmenu.MainMenuHelper {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.tasklog.TaskLogImplImpl {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.timeline.MenuAdapter {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.timeline.MenuModel {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todo.form.GetSchemeTask {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todolist.form.StatusSectionFragment {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todolist.form.TaskListTask {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todolist.form.TaskList_Fragment {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.services.NotificationThread {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todo.form.NewTaskActivity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todo.form.NewTaskAdapter {
|
||||
public protected <methods>;
|
||||
}
|
||||
-keep class com.adins.mss.base.todolist.DoList {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.SynchronizeActivity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.formatter.Formatter {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class androidx.fragment.app.DialogFragment {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.Constant {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.DynamicFormActivity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.SendResultActivity {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.base.dynamicform.TaskManager {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.adins.mss.foundation.questiongenerator.QuestionBean {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
-keep class com.google.gson.JsonSyntaxException {public protected static *; }
|
||||
-keep class com.adins.mss.foundation.db.DaoOpenHelper {public protected static *; }
|
||||
-keep class com.adins.mss.foundation.image.JsonResponseImage {public protected static *; }
|
||||
-keep class com.adins.mss.svy.models.SurveyorSearchResponse {public protected static *;}
|
||||
-keep class com.adins.mss.svy.reassignment.JsonResponseServer {
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.dynamicform.form.questions.OnQuestionClickListener{
|
||||
public protected <methods>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.dynamicform.form.questions.viewholder.ExpandableRecyclerView$GroupViewHolder{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.dynamicform.QuestionSetTask{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.libs.nineoldandroids.view.ViewHelper{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.dynamicform.form.questions.viewholder.ExpandableRecyclerView$Adapter{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.dialogfragments.NewTaskDialog{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.todolist.form.OnTaskListClickListener{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.authentication.Authentication{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.todolist.form.TasklistListener{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.dummy.userhelp_dummy.Adapter.NewTaskLogDummyAdapter{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.dynamicform.TaskManager$ApproveTaskOnBackground{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.base.dynamicform.TaskManager$VerifTaskOnBackground{
|
||||
public protected <methods>;
|
||||
public protected <fields>;
|
||||
}
|
||||
|
||||
#Uncomment if using Serializable
|
||||
-keepclassmembers class * implements java.io.Serializable {
|
||||
private static final java.io.ObjectStreamField[] serialPersistentFields;
|
||||
private void writeObject(java.io.ObjectOutputStream);
|
||||
private void readObject(java.io.ObjectInputStream);
|
||||
java.lang.Object writeReplace();
|
||||
java.lang.Object readResolve();
|
||||
}
|
||||
-keep class * implements java.io.Serializable {
|
||||
public protected <fields>;
|
||||
}
|
||||
#Keep fields for Gson transactions
|
||||
-keep public class * extends com.adins.mss.foundation.http.MssRequestType{
|
||||
<fields>;
|
||||
<methods>;
|
||||
}
|
||||
|
||||
-keep public class * extends RecyclerView.Adapter{
|
||||
<fields>;
|
||||
<methods>;
|
||||
}
|
||||
|
||||
-keep public class * extends com.adins.mss.foundation.http.MssResponseType{
|
||||
<fields>;
|
||||
<methods>;
|
||||
}
|
||||
|
||||
-keep public class com.adins.mss.foundation.UserHelp.** {*;}
|
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.adins.mss.base">
|
||||
|
||||
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_GPS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.front"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.flash"
|
||||
android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.FLASHLIGHT" />
|
||||
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> <!-- External storage for caching. -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><!-- My Location -->
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <!-- agar aplikasi tidak dikill -->
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<application>
|
||||
<receiver
|
||||
android:name="com.receivers.BackupReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false"></receiver>
|
||||
|
||||
<service
|
||||
android:name="com.services.MainServices"
|
||||
android:foregroundServiceType="location"
|
||||
android:exported="false" /> <!-- broadcast receiver -->
|
||||
<receiver
|
||||
android:name="com.services.ServiceAutoRestart"
|
||||
android:directBootAware="true"
|
||||
android:exported="true"
|
||||
android:process=":remote">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".dynamicform.form.DynamicQuestionActivity"
|
||||
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name=".dynamicform.form.questions.DrawingCanvasActivity"
|
||||
android:configChanges="orientation|keyboard|keyboardHidden|screenSize" />
|
||||
<activity android:name=".dynamicform.form.questions.ImageViewerActivity" />
|
||||
<activity
|
||||
android:name="com.adins.mss.printer.main_winson"
|
||||
android:label="@string/title_activity_main_winson" />
|
||||
<activity
|
||||
android:name="zj.com.cn.bluetooth.sdk.Main_Activity1"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name="zj.com.cn.bluetooth.sdk.DeviceListActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/select_device"
|
||||
android:theme="@android:style/Theme.Dialog" /> <!-- LOOKUP ONLINE -->
|
||||
<activity
|
||||
android:name=".dynamicform.form.questions.viewholder.LookupFilterActivity"
|
||||
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name=".dynamicform.form.questions.viewholder.LookupCriteriaOnlineActivity"
|
||||
android:configChanges="orientation|keyboard|keyboardHidden|screenSize" /> <!-- <activity android:name=".NewMainActivity" /> -->
|
||||
<activity android:name=".NewChangePasswordActivity" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:name="com.services.MssJobScheduler"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name="com.services.plantask.StartVisitJob"
|
||||
android:exported="false"/>
|
||||
<service
|
||||
android:name="com.services.plantask.ChangePlanService"
|
||||
android:exported="false"/>
|
||||
|
||||
<uses-library
|
||||
android:name="org.apache.http.legacy"
|
||||
android:required="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
Binary file not shown.
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This is the superclass for classes which provide basic support for animations which can be
|
||||
* started, ended, and have <code>AnimatorListeners</code> added to them.
|
||||
*/
|
||||
public abstract class Animator implements Cloneable {
|
||||
|
||||
|
||||
/**
|
||||
* The set of listeners to be sent events through the life of an animation.
|
||||
*/
|
||||
ArrayList<AnimatorListener> mListeners = null;
|
||||
|
||||
/**
|
||||
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
|
||||
* running after that delay elapses. A non-delayed animation will have its initial
|
||||
* value(s) set immediately, followed by calls to
|
||||
* {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
|
||||
* <p>
|
||||
* <p>The animation started by calling this method will be run on the thread that called
|
||||
* this method. This thread should have a Looper on it (a runtime exception will be thrown if
|
||||
* this is not the case). Also, if the animation will animate
|
||||
* properties of objects in the view hierarchy, then the calling thread should be the UI
|
||||
* thread for that view hierarchy.</p>
|
||||
*/
|
||||
public void start() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to
|
||||
* stop in its tracks, sending an
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to
|
||||
* its listeners, followed by an
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message.
|
||||
* <p>
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the animation. This causes the animation to assign the end value of the property being
|
||||
* animated, then calling the
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on
|
||||
* its listeners.
|
||||
* <p>
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
public void end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, to delay starting the animation after
|
||||
* {@link #start()} is called.
|
||||
*
|
||||
* @return the number of milliseconds to delay running the animation
|
||||
*/
|
||||
public abstract long getStartDelay();
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, to delay starting the animation after
|
||||
* {@link #start()} is called.
|
||||
*
|
||||
* @param startDelay The amount of the delay, in milliseconds
|
||||
*/
|
||||
public abstract void setStartDelay(long startDelay);
|
||||
|
||||
/**
|
||||
* Gets the length of the animation.
|
||||
*
|
||||
* @return The length of the animation, in milliseconds.
|
||||
*/
|
||||
public abstract long getDuration();
|
||||
|
||||
/**
|
||||
* Sets the length of the animation.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
*/
|
||||
public abstract Animator setDuration(long duration);
|
||||
|
||||
/**
|
||||
* The time interpolator used in calculating the elapsed fraction of this animation. The
|
||||
* interpolator determines whether the animation runs with linear or non-linear motion,
|
||||
* such as acceleration and deceleration. The default value is
|
||||
* {@link android.view.animation.AccelerateDecelerateInterpolator}
|
||||
*
|
||||
* @param value the interpolator to be used by this animation
|
||||
*/
|
||||
public abstract void setInterpolator(/*Time*/Interpolator value);
|
||||
|
||||
/**
|
||||
* Returns whether this Animator is currently running (having been started and gone past any
|
||||
* initial startDelay period and not yet ended).
|
||||
*
|
||||
* @return Whether the Animator is running.
|
||||
*/
|
||||
public abstract boolean isRunning();
|
||||
|
||||
/**
|
||||
* Returns whether this Animator has been started and not yet ended. This state is a superset
|
||||
* of the state of {@link #isRunning()}, because an Animator with a nonzero
|
||||
* {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during the
|
||||
* delay phase, whereas {@link #isRunning()} will return true only after the delay phase
|
||||
* is complete.
|
||||
*
|
||||
* @return Whether the Animator has been started and not yet ended.
|
||||
*/
|
||||
public boolean isStarted() {
|
||||
// Default method returns value for isRunning(). Subclasses should override to return a
|
||||
// real value.
|
||||
return isRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the set of listeners that are sent events through the life of an
|
||||
* animation, such as start, repeat, and end.
|
||||
*
|
||||
* @param listener the listener to be added to the current set of listeners for this animation.
|
||||
*/
|
||||
public void addListener(AnimatorListener listener) {
|
||||
if (mListeners == null) {
|
||||
mListeners = new ArrayList<AnimatorListener>();
|
||||
}
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the set listening to this animation.
|
||||
*
|
||||
* @param listener the listener to be removed from the current set of listeners for this
|
||||
* animation.
|
||||
*/
|
||||
public void removeListener(AnimatorListener listener) {
|
||||
if (mListeners == null) {
|
||||
return;
|
||||
}
|
||||
mListeners.remove(listener);
|
||||
if (mListeners.size() == 0) {
|
||||
mListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently
|
||||
* listening for events on this <code>Animator</code> object.
|
||||
*
|
||||
* @return ArrayList<AnimatorListener> The set of listeners.
|
||||
*/
|
||||
public ArrayList<AnimatorListener> getListeners() {
|
||||
return mListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners from this object. This is equivalent to calling
|
||||
* <code>getListeners()</code> followed by calling <code>clear()</code> on the
|
||||
* returned list of listeners.
|
||||
*/
|
||||
public void removeAllListeners() {
|
||||
if (mListeners != null) {
|
||||
mListeners.clear();
|
||||
mListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator clone() {
|
||||
try {
|
||||
final Animator anim = (Animator) super.clone();
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> oldListeners = mListeners;
|
||||
anim.mListeners = new ArrayList<AnimatorListener>();
|
||||
int numListeners = oldListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
anim.mListeners.add(oldListeners.get(i));
|
||||
}
|
||||
}
|
||||
return anim;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* starting values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* An ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
public void setupStartValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* ending values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* An ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
public void setupEndValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target object whose property will be animated by this animation. Not all subclasses
|
||||
* operate on target objects (for example, {@link ValueAnimator}, but this method
|
||||
* is on the superclass for the convenience of dealing generically with those subclasses
|
||||
* that do handle targets.
|
||||
*
|
||||
* @param target The object being animated
|
||||
*/
|
||||
public void setTarget(Object target) {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>An animation listener receives notifications from an animation.
|
||||
* Notifications indicate animation related events, such as the end or the
|
||||
* repetition of the animation.</p>
|
||||
*/
|
||||
public static interface AnimatorListener {
|
||||
/**
|
||||
* <p>Notifies the start of the animation.</p>
|
||||
*
|
||||
* @param animation The started animation.
|
||||
*/
|
||||
void onAnimationStart(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the end of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*
|
||||
* @param animation The animation which reached its end.
|
||||
*/
|
||||
void onAnimationEnd(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the cancellation of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*
|
||||
* @param animation The animation which was canceled.
|
||||
*/
|
||||
void onAnimationCancel(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the repetition of the animation.</p>
|
||||
*
|
||||
* @param animation The animation which was repeated.
|
||||
*/
|
||||
void onAnimationRepeat(Animator animation);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.util.Xml;
|
||||
import android.view.animation.AnimationUtils;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class is used to instantiate animator XML files into Animator objects.
|
||||
* <p>
|
||||
* For performance reasons, inflation relies heavily on pre-processing of
|
||||
* XML files that is done at build time. Therefore, it is not currently possible
|
||||
* to use this inflater with an XmlPullParser over a plain XML file at runtime;
|
||||
* it only works with an XmlPullParser returned from a compiled resource (R.
|
||||
* <em>something</em> file.)
|
||||
*/
|
||||
public class AnimatorInflater {
|
||||
private static final int[] AnimatorSet = new int[]{
|
||||
/* 0 */ android.R.attr.ordering,
|
||||
};
|
||||
private static final int AnimatorSet_ordering = 0;
|
||||
|
||||
private static final int[] PropertyAnimator = new int[]{
|
||||
/* 0 */ android.R.attr.propertyName,
|
||||
};
|
||||
private static final int PropertyAnimator_propertyName = 0;
|
||||
|
||||
private static final int[] Animator = new int[]{
|
||||
/* 0 */ android.R.attr.interpolator,
|
||||
/* 1 */ android.R.attr.duration,
|
||||
/* 2 */ android.R.attr.startOffset,
|
||||
/* 3 */ android.R.attr.repeatCount,
|
||||
/* 4 */ android.R.attr.repeatMode,
|
||||
/* 5 */ android.R.attr.valueFrom,
|
||||
/* 6 */ android.R.attr.valueTo,
|
||||
/* 7 */ android.R.attr.valueType,
|
||||
};
|
||||
private static final int Animator_interpolator = 0;
|
||||
private static final int Animator_duration = 1;
|
||||
private static final int Animator_startOffset = 2;
|
||||
private static final int Animator_repeatCount = 3;
|
||||
private static final int Animator_repeatMode = 4;
|
||||
private static final int Animator_valueFrom = 5;
|
||||
private static final int Animator_valueTo = 6;
|
||||
private static final int Animator_valueType = 7;
|
||||
|
||||
/**
|
||||
* These flags are used when parsing AnimatorSet objects
|
||||
*/
|
||||
private static final int TOGETHER = 0;
|
||||
//private static final int SEQUENTIALLY = 1;
|
||||
|
||||
/**
|
||||
* Enum values used in XML attributes to indicate the value for mValueType
|
||||
*/
|
||||
private static final int VALUE_TYPE_FLOAT = 0;
|
||||
//private static final int VALUE_TYPE_INT = 1;
|
||||
//private static final int VALUE_TYPE_COLOR = 4;
|
||||
//private static final int VALUE_TYPE_CUSTOM = 5;
|
||||
|
||||
/**
|
||||
* Loads an {@link Animator} object from a resource
|
||||
*
|
||||
* @param context Application context used to access resources
|
||||
* @param id The resource id of the animation to load
|
||||
* @return The animator object reference by the specified id
|
||||
* @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
|
||||
*/
|
||||
public static Animator loadAnimator(Context context, int id)
|
||||
throws NotFoundException {
|
||||
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
parser = context.getResources().getAnimation(id);
|
||||
return createAnimatorFromXml(context, parser);
|
||||
} catch (XmlPullParserException ex) {
|
||||
Resources.NotFoundException rnf =
|
||||
new Resources.NotFoundException("Can't load animation resource ID #0x" +
|
||||
Integer.toHexString(id));
|
||||
rnf.initCause(ex);
|
||||
throw rnf;
|
||||
} catch (IOException ex) {
|
||||
Resources.NotFoundException rnf =
|
||||
new Resources.NotFoundException("Can't load animation resource ID #0x" +
|
||||
Integer.toHexString(id));
|
||||
rnf.initCause(ex);
|
||||
throw rnf;
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
|
||||
}
|
||||
|
||||
private static Animator createAnimatorFromXml(Context c, XmlPullParser parser,
|
||||
AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
Animator anim = null;
|
||||
ArrayList<Animator> childAnims = null;
|
||||
|
||||
// Make sure we are on a start tag.
|
||||
int type;
|
||||
int depth = parser.getDepth();
|
||||
|
||||
while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
|
||||
&& type != XmlPullParser.END_DOCUMENT) {
|
||||
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = parser.getName();
|
||||
|
||||
if (name.equals("objectAnimator")) {
|
||||
anim = loadObjectAnimator(c, attrs);
|
||||
} else if (name.equals("animator")) {
|
||||
anim = loadAnimator(c, attrs, null);
|
||||
} else if (name.equals("set")) {
|
||||
anim = new AnimatorSet();
|
||||
TypedArray a = c.obtainStyledAttributes(attrs,
|
||||
/*com.android.internal.R.styleable.*/AnimatorSet);
|
||||
|
||||
TypedValue orderingValue = new TypedValue();
|
||||
a.getValue(/*com.android.internal.R.styleable.*/AnimatorSet_ordering, orderingValue);
|
||||
int ordering = orderingValue.type == TypedValue.TYPE_INT_DEC ? orderingValue.data : TOGETHER;
|
||||
|
||||
createAnimatorFromXml(c, parser, attrs, (AnimatorSet) anim, ordering);
|
||||
a.recycle();
|
||||
} else {
|
||||
throw new RuntimeException("Unknown animator name: " + parser.getName());
|
||||
}
|
||||
|
||||
if (parent != null) {
|
||||
if (childAnims == null) {
|
||||
childAnims = new ArrayList<Animator>();
|
||||
}
|
||||
childAnims.add(anim);
|
||||
}
|
||||
}
|
||||
if (parent != null && childAnims != null) {
|
||||
Animator[] animsArray = new Animator[childAnims.size()];
|
||||
int index = 0;
|
||||
for (Animator a : childAnims) {
|
||||
animsArray[index++] = a;
|
||||
}
|
||||
if (sequenceOrdering == TOGETHER) {
|
||||
parent.playTogether(animsArray);
|
||||
} else {
|
||||
parent.playSequentially(animsArray);
|
||||
}
|
||||
}
|
||||
|
||||
return anim;
|
||||
|
||||
}
|
||||
|
||||
private static ObjectAnimator loadObjectAnimator(Context context, AttributeSet attrs)
|
||||
throws NotFoundException {
|
||||
|
||||
ObjectAnimator anim = new ObjectAnimator();
|
||||
|
||||
loadAnimator(context, attrs, anim);
|
||||
|
||||
TypedArray a =
|
||||
context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/PropertyAnimator);
|
||||
|
||||
String propertyName = a.getString(/*com.android.internal.R.styleable.*/PropertyAnimator_propertyName);
|
||||
|
||||
anim.setPropertyName(propertyName);
|
||||
|
||||
a.recycle();
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new animation whose parameters come from the specified context and
|
||||
* attributes set.
|
||||
*
|
||||
* @param context the application environment
|
||||
* @param attrs the set of attributes holding the animation parameters
|
||||
*/
|
||||
private static ValueAnimator loadAnimator(Context context, AttributeSet attrs, ValueAnimator anim)
|
||||
throws NotFoundException {
|
||||
|
||||
TypedArray a =
|
||||
context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/Animator);
|
||||
|
||||
long duration = a.getInt(/*com.android.internal.R.styleable.*/Animator_duration, 0);
|
||||
|
||||
long startDelay = a.getInt(/*com.android.internal.R.styleable.*/Animator_startOffset, 0);
|
||||
|
||||
int valueType = a.getInt(/*com.android.internal.R.styleable.*/Animator_valueType,
|
||||
VALUE_TYPE_FLOAT);
|
||||
|
||||
if (anim == null) {
|
||||
anim = new ValueAnimator();
|
||||
}
|
||||
//TypeEvaluator evaluator = null;
|
||||
|
||||
int valueFromIndex = /*com.android.internal.R.styleable.*/Animator_valueFrom;
|
||||
int valueToIndex = /*com.android.internal.R.styleable.*/Animator_valueTo;
|
||||
|
||||
boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
|
||||
|
||||
TypedValue tvFrom = a.peekValue(valueFromIndex);
|
||||
boolean hasFrom = (tvFrom != null);
|
||||
int fromType = hasFrom ? tvFrom.type : 0;
|
||||
TypedValue tvTo = a.peekValue(valueToIndex);
|
||||
boolean hasTo = (tvTo != null);
|
||||
int toType = hasTo ? tvTo.type : 0;
|
||||
|
||||
if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
|
||||
(hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
|
||||
// special case for colors: ignore valueType and get ints
|
||||
getFloats = false;
|
||||
anim.setEvaluator(new ArgbEvaluator());
|
||||
}
|
||||
|
||||
if (getFloats) {
|
||||
float valueFrom;
|
||||
float valueTo;
|
||||
if (hasFrom) {
|
||||
if (fromType == TypedValue.TYPE_DIMENSION) {
|
||||
valueFrom = a.getDimension(valueFromIndex, 0f);
|
||||
} else {
|
||||
valueFrom = a.getFloat(valueFromIndex, 0f);
|
||||
}
|
||||
if (hasTo) {
|
||||
if (toType == TypedValue.TYPE_DIMENSION) {
|
||||
valueTo = a.getDimension(valueToIndex, 0f);
|
||||
} else {
|
||||
valueTo = a.getFloat(valueToIndex, 0f);
|
||||
}
|
||||
anim.setFloatValues(valueFrom, valueTo);
|
||||
} else {
|
||||
anim.setFloatValues(valueFrom);
|
||||
}
|
||||
} else {
|
||||
if (toType == TypedValue.TYPE_DIMENSION) {
|
||||
valueTo = a.getDimension(valueToIndex, 0f);
|
||||
} else {
|
||||
valueTo = a.getFloat(valueToIndex, 0f);
|
||||
}
|
||||
anim.setFloatValues(valueTo);
|
||||
}
|
||||
} else {
|
||||
int valueFrom;
|
||||
int valueTo;
|
||||
if (hasFrom) {
|
||||
if (fromType == TypedValue.TYPE_DIMENSION) {
|
||||
valueFrom = (int) a.getDimension(valueFromIndex, 0f);
|
||||
} else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
|
||||
valueFrom = a.getColor(valueFromIndex, 0);
|
||||
} else {
|
||||
valueFrom = a.getInt(valueFromIndex, 0);
|
||||
}
|
||||
if (hasTo) {
|
||||
if (toType == TypedValue.TYPE_DIMENSION) {
|
||||
valueTo = (int) a.getDimension(valueToIndex, 0f);
|
||||
} else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
|
||||
valueTo = a.getColor(valueToIndex, 0);
|
||||
} else {
|
||||
valueTo = a.getInt(valueToIndex, 0);
|
||||
}
|
||||
anim.setIntValues(valueFrom, valueTo);
|
||||
} else {
|
||||
anim.setIntValues(valueFrom);
|
||||
}
|
||||
} else {
|
||||
if (hasTo) {
|
||||
if (toType == TypedValue.TYPE_DIMENSION) {
|
||||
valueTo = (int) a.getDimension(valueToIndex, 0f);
|
||||
} else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
|
||||
valueTo = a.getColor(valueToIndex, 0);
|
||||
} else {
|
||||
valueTo = a.getInt(valueToIndex, 0);
|
||||
}
|
||||
anim.setIntValues(valueTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anim.setDuration(duration);
|
||||
anim.setStartDelay(startDelay);
|
||||
|
||||
if (a.hasValue(/*com.android.internal.R.styleable.*/Animator_repeatCount)) {
|
||||
anim.setRepeatCount(
|
||||
a.getInt(/*com.android.internal.R.styleable.*/Animator_repeatCount, 0));
|
||||
}
|
||||
if (a.hasValue(/*com.android.internal.R.styleable.*/Animator_repeatMode)) {
|
||||
anim.setRepeatMode(
|
||||
a.getInt(/*com.android.internal.R.styleable.*/Animator_repeatMode,
|
||||
ValueAnimator.RESTART));
|
||||
}
|
||||
//if (evaluator != null) {
|
||||
// anim.setEvaluator(evaluator);
|
||||
//}
|
||||
|
||||
final int resID =
|
||||
a.getResourceId(/*com.android.internal.R.styleable.*/Animator_interpolator, 0);
|
||||
if (resID > 0) {
|
||||
anim.setInterpolator(AnimationUtils.loadInterpolator(context, resID));
|
||||
}
|
||||
a.recycle();
|
||||
|
||||
return anim;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This adapter class provides empty implementations of the methods from {@link android.animation.Animator.AnimatorListener}.
|
||||
* Any custom listener that cares only about a subset of the methods of this listener can
|
||||
* simply subclass this adapter class instead of implementing the interface directly.
|
||||
*/
|
||||
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between integer
|
||||
* values that represent ARGB colors.
|
||||
*/
|
||||
public class ArgbEvaluator implements TypeEvaluator {
|
||||
|
||||
/**
|
||||
* This function returns the calculated in-between value for a color
|
||||
* given integers that represent the start and end values in the four
|
||||
* bytes of the 32-bit int. Each channel is separately linearly interpolated
|
||||
* and the resulting calculated values are recombined into the return value.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue A 32-bit int value representing colors in the
|
||||
* separate bytes of the parameter
|
||||
* @param endValue A 32-bit int value representing colors in the
|
||||
* separate bytes of the parameter
|
||||
* @return A value that is calculated to be the linearly interpolated
|
||||
* result, derived by separating the start and end values into separate
|
||||
* color channels and interpolating each one separately, recombining the
|
||||
* resulting values in the same way.
|
||||
*/
|
||||
public Object evaluate(float fraction, Object startValue, Object endValue) {
|
||||
int startInt = (Integer) startValue;
|
||||
int startA = (startInt >> 24);
|
||||
int startR = (startInt >> 16) & 0xff;
|
||||
int startG = (startInt >> 8) & 0xff;
|
||||
int startB = startInt & 0xff;
|
||||
|
||||
int endInt = (Integer) endValue;
|
||||
int endA = (endInt >> 24);
|
||||
int endR = (endInt >> 16) & 0xff;
|
||||
int endG = (endInt >> 8) & 0xff;
|
||||
int endB = endInt & 0xff;
|
||||
|
||||
return (int) ((startA + (int) (fraction * (endA - startA))) << 24) |
|
||||
(int) ((startR + (int) (fraction * (endR - startR))) << 16) |
|
||||
(int) ((startG + (int) (fraction * (endG - startG))) << 8) |
|
||||
(int) ((startB + (int) (fraction * (endB - startB))));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between <code>float</code> values.
|
||||
*/
|
||||
public class FloatEvaluator implements TypeEvaluator<Number> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value; should be of type <code>float</code> or
|
||||
* <code>Float</code>
|
||||
* @param endValue The end value; should be of type <code>float</code> or <code>Float</code>
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public Float evaluate(float fraction, Number startValue, Number endValue) {
|
||||
float startFloat = startValue.floatValue();
|
||||
return startFloat + fraction * (endValue.floatValue() - startFloat);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.adins.libs.nineoldandroids.animation.Keyframe.FloatKeyframe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
* <p>
|
||||
* <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
|
||||
* int, exists to speed up the getValue() method when there is no custom
|
||||
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
|
||||
* Object equivalents of these primitive types.</p>
|
||||
*/
|
||||
class FloatKeyframeSet extends KeyframeSet {
|
||||
private float firstValue;
|
||||
private float lastValue;
|
||||
private float deltaValue;
|
||||
private boolean firstTime = true;
|
||||
|
||||
public FloatKeyframeSet(FloatKeyframe... keyframes) {
|
||||
super(keyframes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(float fraction) {
|
||||
return getFloatValue(fraction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatKeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone();
|
||||
}
|
||||
FloatKeyframeSet newSet = new FloatKeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
public float getFloatValue(float fraction) {
|
||||
if (mNumKeyframes == 2) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue();
|
||||
lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue();
|
||||
deltaValue = lastValue - firstValue;
|
||||
}
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
if (mEvaluator == null) {
|
||||
return firstValue + fraction * deltaValue;
|
||||
} else {
|
||||
return ((Number) mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue();
|
||||
}
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number) mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
} else if (fraction >= 1f) {
|
||||
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number) mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
}
|
||||
FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number) mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return ((Number) mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between <code>int</code> values.
|
||||
*/
|
||||
public class IntEvaluator implements TypeEvaluator<Integer> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value; should be of type <code>int</code> or
|
||||
* <code>Integer</code>
|
||||
* @param endValue The end value; should be of type <code>int</code> or <code>Integer</code>
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
|
||||
int startInt = startValue;
|
||||
return (int) (startInt + fraction * (endValue - startInt));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.adins.libs.nineoldandroids.animation.Keyframe.IntKeyframe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
* <p>
|
||||
* <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
|
||||
* float, exists to speed up the getValue() method when there is no custom
|
||||
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
|
||||
* Object equivalents of these primitive types.</p>
|
||||
*/
|
||||
class IntKeyframeSet extends KeyframeSet {
|
||||
private int firstValue;
|
||||
private int lastValue;
|
||||
private int deltaValue;
|
||||
private boolean firstTime = true;
|
||||
|
||||
public IntKeyframeSet(IntKeyframe... keyframes) {
|
||||
super(keyframes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(float fraction) {
|
||||
return getIntValue(fraction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntKeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = (IntKeyframe) keyframes.get(i).clone();
|
||||
}
|
||||
IntKeyframeSet newSet = new IntKeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
public int getIntValue(float fraction) {
|
||||
if (mNumKeyframes == 2) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
|
||||
lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
|
||||
deltaValue = lastValue - firstValue;
|
||||
}
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
if (mEvaluator == null) {
|
||||
return firstValue + (int) (fraction * deltaValue);
|
||||
} else {
|
||||
return ((Number) mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
|
||||
}
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1);
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int) (intervalFraction * (nextValue - prevValue)) :
|
||||
((Number) mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
intValue();
|
||||
} else if (fraction >= 1f) {
|
||||
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int) (intervalFraction * (nextValue - prevValue)) :
|
||||
((Number) mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();
|
||||
}
|
||||
IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int) (intervalFraction * (nextValue - prevValue)) :
|
||||
((Number) mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
intValue();
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return ((Number) mKeyframes.get(mNumKeyframes - 1).getValue()).intValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This class holds a time/value pair for an animation. The Keyframe class is used
|
||||
* by {@link ValueAnimator} to define the values that the animation target will have over the course
|
||||
* of the animation. As the time proceeds from one keyframe to the other, the value of the
|
||||
* target object will animate between the value at the previous keyframe and the value at the
|
||||
* next keyframe. Each keyframe also holds an optional {@link TimeInterpolator}
|
||||
* object, which defines the time interpolation over the intervalue preceding the keyframe.
|
||||
* <p>
|
||||
* <p>The Keyframe class itself is abstract. The type-specific factory methods will return
|
||||
* a subclass of Keyframe specific to the type of value being stored. This is done to improve
|
||||
* performance when dealing with the most common cases (e.g., <code>float</code> and
|
||||
* <code>int</code> values). Other types will fall into a more general Keyframe class that
|
||||
* treats its values as Objects. Unless your animation requires dealing with a custom type
|
||||
* or a data structure that needs to be animated directly (and evaluated using an implementation
|
||||
* of {@link TypeEvaluator}), you should stick to using float and int as animations using those
|
||||
* types have lower runtime overhead than other types.</p>
|
||||
*/
|
||||
public abstract class Keyframe implements Cloneable {
|
||||
/**
|
||||
* The time at which mValue will hold true.
|
||||
*/
|
||||
float mFraction;
|
||||
|
||||
/**
|
||||
* The type of the value in this Keyframe. This type is determined at construction time,
|
||||
* based on the type of the <code>value</code> object passed into the constructor.
|
||||
*/
|
||||
Class mValueType;
|
||||
/**
|
||||
* Flag to indicate whether this keyframe has a valid value. This flag is used when an
|
||||
* animation first starts, to populate placeholder keyframes with real values derived
|
||||
* from the target object.
|
||||
*/
|
||||
boolean mHasValue = false;
|
||||
/**
|
||||
* The optional time interpolator for the interval preceding this keyframe. A null interpolator
|
||||
* (the default) results in linear interpolation over the interval.
|
||||
*/
|
||||
private /*Time*/ Interpolator mInterpolator = null;
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofInt(float fraction, int value) {
|
||||
return new IntKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofInt(float fraction) {
|
||||
return new IntKeyframe(fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofFloat(float fraction, float value) {
|
||||
return new FloatKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofFloat(float fraction) {
|
||||
return new FloatKeyframe(fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofObject(float fraction, Object value) {
|
||||
return new ObjectKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofObject(float fraction) {
|
||||
return new ObjectKeyframe(fraction, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this keyframe has a valid value. This method is called internally when
|
||||
* an {@link ObjectAnimator} first starts; keyframes without values are assigned values at
|
||||
* that time by deriving the value for the property from the target object.
|
||||
*
|
||||
* @return boolean Whether this object has a value assigned.
|
||||
*/
|
||||
public boolean hasValue() {
|
||||
return mHasValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for this Keyframe.
|
||||
*
|
||||
* @return The value for this Keyframe.
|
||||
*/
|
||||
public abstract Object getValue();
|
||||
|
||||
/**
|
||||
* Sets the value for this Keyframe.
|
||||
*
|
||||
* @param value value for this Keyframe.
|
||||
*/
|
||||
public abstract void setValue(Object value);
|
||||
|
||||
/**
|
||||
* Gets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @return The time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public float getFraction() {
|
||||
return mFraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @param fraction time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public void setFraction(float fraction) {
|
||||
mFraction = fraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public /*Time*/Interpolator getInterpolator() {
|
||||
return mInterpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public void setInterpolator(/*Time*/Interpolator interpolator) {
|
||||
mInterpolator = interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of keyframe. This information is used by ValueAnimator to determine the type of
|
||||
* {@link TypeEvaluator} to use when calculating values between keyframes. The type is based
|
||||
* on the type of Keyframe created.
|
||||
*
|
||||
* @return The type of the value stored in the Keyframe.
|
||||
*/
|
||||
public Class getType() {
|
||||
return mValueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Keyframe clone();
|
||||
|
||||
/**
|
||||
* This internal subclass is used for all types which are not int or float.
|
||||
*/
|
||||
static class ObjectKeyframe extends Keyframe {
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
Object mValue;
|
||||
|
||||
ObjectKeyframe(float fraction, Object value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mHasValue = (value != null);
|
||||
mValueType = mHasValue ? value.getClass() : Object.class;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
mValue = value;
|
||||
mHasValue = (value != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectKeyframe clone() {
|
||||
ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal subclass used when the keyframe value is of type int.
|
||||
*/
|
||||
static class IntKeyframe extends Keyframe {
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
int mValue;
|
||||
|
||||
IntKeyframe(float fraction, int value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = int.class;
|
||||
mHasValue = true;
|
||||
}
|
||||
|
||||
IntKeyframe(float fraction) {
|
||||
mFraction = fraction;
|
||||
mValueType = int.class;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (value != null && value.getClass() == Integer.class) {
|
||||
mValue = ((Integer) value).intValue();
|
||||
mHasValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntKeyframe clone() {
|
||||
IntKeyframe kfClone = new IntKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal subclass used when the keyframe value is of type float.
|
||||
*/
|
||||
static class FloatKeyframe extends Keyframe {
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
float mValue;
|
||||
|
||||
FloatKeyframe(float fraction, float value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = float.class;
|
||||
mHasValue = true;
|
||||
}
|
||||
|
||||
FloatKeyframe(float fraction) {
|
||||
mFraction = fraction;
|
||||
mValueType = float.class;
|
||||
}
|
||||
|
||||
public float getFloatValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (value != null && value.getClass() == Float.class) {
|
||||
mValue = ((Float) value).floatValue();
|
||||
mHasValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatKeyframe clone() {
|
||||
FloatKeyframe kfClone = new FloatKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.adins.libs.nineoldandroids.animation.Keyframe.FloatKeyframe;
|
||||
import com.adins.libs.nineoldandroids.animation.Keyframe.IntKeyframe;
|
||||
import com.adins.libs.nineoldandroids.animation.Keyframe.ObjectKeyframe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*/
|
||||
class KeyframeSet {
|
||||
|
||||
int mNumKeyframes;
|
||||
|
||||
Keyframe mFirstKeyframe;
|
||||
Keyframe mLastKeyframe;
|
||||
/*Time*/ Interpolator mInterpolator; // only used in the 2-keyframe case
|
||||
ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
|
||||
TypeEvaluator mEvaluator;
|
||||
|
||||
|
||||
public KeyframeSet(Keyframe... keyframes) {
|
||||
mNumKeyframes = keyframes.length;
|
||||
mKeyframes = new ArrayList<Keyframe>();
|
||||
mKeyframes.addAll(Arrays.asList(keyframes));
|
||||
mFirstKeyframe = mKeyframes.get(0);
|
||||
mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
|
||||
mInterpolator = mLastKeyframe.getInterpolator();
|
||||
}
|
||||
|
||||
public static KeyframeSet ofInt(int... values) {
|
||||
int numKeyframes = values.length;
|
||||
IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes, 2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
|
||||
keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new IntKeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
public static KeyframeSet ofFloat(float... values) {
|
||||
int numKeyframes = values.length;
|
||||
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes, 2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
|
||||
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new FloatKeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
public static KeyframeSet ofKeyframe(Keyframe... keyframes) {
|
||||
// if all keyframes of same primitive type, create the appropriate KeyframeSet
|
||||
int numKeyframes = keyframes.length;
|
||||
boolean hasFloat = false;
|
||||
boolean hasInt = false;
|
||||
boolean hasOther = false;
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
if (keyframes[i] instanceof FloatKeyframe) {
|
||||
hasFloat = true;
|
||||
} else if (keyframes[i] instanceof IntKeyframe) {
|
||||
hasInt = true;
|
||||
} else {
|
||||
hasOther = true;
|
||||
}
|
||||
}
|
||||
if (hasFloat && !hasInt && !hasOther) {
|
||||
FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
floatKeyframes[i] = (FloatKeyframe) keyframes[i];
|
||||
}
|
||||
return new FloatKeyframeSet(floatKeyframes);
|
||||
} else if (hasInt && !hasFloat && !hasOther) {
|
||||
IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
intKeyframes[i] = (IntKeyframe) keyframes[i];
|
||||
}
|
||||
return new IntKeyframeSet(intKeyframes);
|
||||
} else {
|
||||
return new KeyframeSet(keyframes);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyframeSet ofObject(Object... values) {
|
||||
int numKeyframes = values.length;
|
||||
ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes, 2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f);
|
||||
keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new KeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TypeEvaluator to be used when calculating animated values. This object
|
||||
* is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
|
||||
* both of which assume their own evaluator to speed up calculations with those primitive
|
||||
* types.
|
||||
*
|
||||
* @param evaluator The TypeEvaluator to be used to calculate animated values.
|
||||
*/
|
||||
public void setEvaluator(TypeEvaluator evaluator) {
|
||||
mEvaluator = evaluator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
Keyframe[] newKeyframes = new Keyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = keyframes.get(i).clone();
|
||||
}
|
||||
KeyframeSet newSet = new KeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the animated value, given the elapsed fraction of the animation (interpolated by the
|
||||
* animation's interpolator) and the evaluator used to calculate in-between values. This
|
||||
* function maps the input fraction to the appropriate keyframe interval and a fraction
|
||||
* between them and returns the interpolated value. Note that the input fraction may fall
|
||||
* outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
|
||||
* spring interpolation that might send the fraction past 1.0). We handle this situation by
|
||||
* just using the two keyframes at the appropriate end when the value is outside those bounds.
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation
|
||||
* @return The animated value.
|
||||
*/
|
||||
public Object getValue(float fraction) {
|
||||
|
||||
// Special-case optimization for the common case of only two keyframes
|
||||
if (mNumKeyframes == 2) {
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
|
||||
mLastKeyframe.getValue());
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final Keyframe nextKeyframe = mKeyframes.get(1);
|
||||
final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = mFirstKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(nextKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
} else if (fraction >= 1f) {
|
||||
final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
|
||||
final /*Time*/ Interpolator interpolator = mLastKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = prevKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(mLastKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
mLastKeyframe.getValue());
|
||||
}
|
||||
Keyframe prevKeyframe = mFirstKeyframe;
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
Keyframe nextKeyframe = mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/ Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = prevKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(nextKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't reach here
|
||||
return mLastKeyframe.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String returnVal = " ";
|
||||
for (int i = 0; i < mNumKeyframes; ++i) {
|
||||
returnVal += mKeyframes.get(i).getValue() + " ";
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.adins.libs.nineoldandroids.util.Property;
|
||||
import com.adins.libs.nineoldandroids.view.animation.AnimatorProxy;
|
||||
import com.adins.mss.foundation.camerainapp.helper.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
|
||||
* The constructors of this class take parameters to define the target object that will be animated
|
||||
* as well as the name of the property that will be animated. Appropriate set/get functions
|
||||
* are then determined internally and the animation will call these functions as necessary to
|
||||
* animate the property.
|
||||
*
|
||||
* @see #setPropertyName(String)
|
||||
*/
|
||||
public final class ObjectAnimator extends ValueAnimator {
|
||||
private static final boolean DBG = false;
|
||||
private static final Map<String, Property> PROXY_PROPERTIES = new HashMap<String, Property>();
|
||||
|
||||
static {
|
||||
PROXY_PROPERTIES.put("alpha", PreHoneycombCompat.ALPHA);
|
||||
PROXY_PROPERTIES.put("pivotX", PreHoneycombCompat.PIVOT_X);
|
||||
PROXY_PROPERTIES.put("pivotY", PreHoneycombCompat.PIVOT_Y);
|
||||
PROXY_PROPERTIES.put("translationX", PreHoneycombCompat.TRANSLATION_X);
|
||||
PROXY_PROPERTIES.put("translationY", PreHoneycombCompat.TRANSLATION_Y);
|
||||
PROXY_PROPERTIES.put("rotation", PreHoneycombCompat.ROTATION);
|
||||
PROXY_PROPERTIES.put("rotationX", PreHoneycombCompat.ROTATION_X);
|
||||
PROXY_PROPERTIES.put("rotationY", PreHoneycombCompat.ROTATION_Y);
|
||||
PROXY_PROPERTIES.put("scaleX", PreHoneycombCompat.SCALE_X);
|
||||
PROXY_PROPERTIES.put("scaleY", PreHoneycombCompat.SCALE_Y);
|
||||
PROXY_PROPERTIES.put("scrollX", PreHoneycombCompat.SCROLL_X);
|
||||
PROXY_PROPERTIES.put("scrollY", PreHoneycombCompat.SCROLL_Y);
|
||||
PROXY_PROPERTIES.put("x", PreHoneycombCompat.X);
|
||||
PROXY_PROPERTIES.put("y", PreHoneycombCompat.Y);
|
||||
}
|
||||
|
||||
// The target object on which the property exists, set in the constructor
|
||||
private Object mTarget;
|
||||
|
||||
private String mPropertyName;
|
||||
|
||||
private Property mProperty;
|
||||
|
||||
/**
|
||||
* Creates a new ObjectAnimator object. This default constructor is primarily for
|
||||
* use internally; the other constructors which take parameters are more generally
|
||||
* useful.
|
||||
*/
|
||||
public ObjectAnimator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private utility constructor that initializes the target object and name of the
|
||||
* property being animated.
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
*/
|
||||
private ObjectAnimator(Object target, String propertyName) {
|
||||
mTarget = target;
|
||||
setPropertyName(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private utility constructor that initializes the target object and property being animated.
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
*/
|
||||
private <T> ObjectAnimator(T target, Property<T, ?> property) {
|
||||
mTarget = target;
|
||||
setProperty(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between int values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setIntValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between int values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
anim.setIntValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between float values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setFloatValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between float values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
|
||||
float... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
anim.setFloatValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between Object values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param evaluator A TypeEvaluator that will be called on each animation frame to
|
||||
* provide the necessary interpolation between the Object values to derive the animated
|
||||
* value.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofObject(Object target, String propertyName,
|
||||
TypeEvaluator evaluator, Object... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setObjectValues(values);
|
||||
anim.setEvaluator(evaluator);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between Object values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param evaluator A TypeEvaluator that will be called on each animation frame to
|
||||
* provide the necessary interpolation between the Object values to derive the animated
|
||||
* value.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
|
||||
TypeEvaluator<V> evaluator, V... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
anim.setObjectValues(values);
|
||||
anim.setEvaluator(evaluator);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between the sets of values specified
|
||||
* in <code>PropertyValueHolder</code> objects. This variant should be used when animating
|
||||
* several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows
|
||||
* you to associate a set of animation values with a property name.
|
||||
*
|
||||
* @param target The object whose property is to be animated. Depending on how the
|
||||
* PropertyValuesObjects were constructed, the target object should either have the {@link
|
||||
* android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the
|
||||
* PropertyValuesHOlder objects were created with property names) the target object should have
|
||||
* public methods on it called <code>setName()</code>, where <code>name</code> is the name of
|
||||
* the property passed in as the <code>propertyName</code> parameter for each of the
|
||||
* PropertyValuesHolder objects.
|
||||
* @param values A set of PropertyValuesHolder objects whose values will be animated between
|
||||
* over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofPropertyValuesHolder(Object target,
|
||||
PropertyValuesHolder... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator();
|
||||
anim.mTarget = target;
|
||||
anim.setValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property that will be animated. Property objects will take precedence over
|
||||
* properties specified by the {@link #setPropertyName(String)} method. Animations should
|
||||
* be set up to use one or the other, not both.
|
||||
*
|
||||
* @param property The property being animated. Should not be null.
|
||||
*/
|
||||
public void setProperty(Property property) {
|
||||
// mValues could be null if this is being constructed piecemeal. Just record the
|
||||
// propertyName to be used later when setValues() is called if so.
|
||||
if (mValues != null) {
|
||||
PropertyValuesHolder valuesHolder = mValues[0];
|
||||
String oldName = valuesHolder.getPropertyName();
|
||||
valuesHolder.setProperty(property);
|
||||
mValuesMap.remove(oldName);
|
||||
mValuesMap.put(mPropertyName, valuesHolder);
|
||||
}
|
||||
if (mProperty != null) {
|
||||
mPropertyName = property.getName();
|
||||
}
|
||||
mProperty = property;
|
||||
// New property/values/target should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the property that will be animated. This name will be used to derive
|
||||
* a setter function that will be called to set animated values.
|
||||
* For example, a property name of <code>foo</code> will result
|
||||
* in a call to the function <code>setFoo()</code> on the target object. If either
|
||||
* <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
|
||||
* also be derived and called.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return mPropertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the property that will be animated. This name is used to derive
|
||||
* a setter function that will be called to set animated values.
|
||||
* For example, a property name of <code>foo</code> will result
|
||||
* in a call to the function <code>setFoo()</code> on the target object. If either
|
||||
* <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
|
||||
* also be derived and called.
|
||||
* <p>
|
||||
* <p>For best performance of the mechanism that calls the setter function determined by the
|
||||
* name of the property being animated, use <code>float</code> or <code>int</code> typed values,
|
||||
* and make the setter function for those properties have a <code>void</code> return value. This
|
||||
* will cause the code to take an optimized path for these constrained circumstances. Other
|
||||
* property types and return types will work, but will have more overhead in processing
|
||||
* the requests due to normal reflection mechanisms.</p>
|
||||
* <p>
|
||||
* <p>Note that the setter function derived from this property name
|
||||
* must take the same parameter type as the
|
||||
* <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
|
||||
* the setter function will fail.</p>
|
||||
* <p>
|
||||
* <p>If this ObjectAnimator has been set up to animate several properties together,
|
||||
* using more than one PropertyValuesHolder objects, then setting the propertyName simply
|
||||
* sets the propertyName in the first of those PropertyValuesHolder objects.</p>
|
||||
*
|
||||
* @param propertyName The name of the property being animated. Should not be null.
|
||||
*/
|
||||
public void setPropertyName(String propertyName) {
|
||||
// mValues could be null if this is being constructed piecemeal. Just record the
|
||||
// propertyName to be used later when setValues() is called if so.
|
||||
if (mValues != null) {
|
||||
PropertyValuesHolder valuesHolder = mValues[0];
|
||||
String oldName = valuesHolder.getPropertyName();
|
||||
valuesHolder.setPropertyName(propertyName);
|
||||
mValuesMap.remove(oldName);
|
||||
mValuesMap.put(propertyName, valuesHolder);
|
||||
}
|
||||
mPropertyName = propertyName;
|
||||
// New property/values/target should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntValues(int... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
if (mProperty != null) {
|
||||
setValues(PropertyValuesHolder.ofInt(mProperty, values));
|
||||
} else {
|
||||
setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
|
||||
}
|
||||
} else {
|
||||
super.setIntValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloatValues(float... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
if (mProperty != null) {
|
||||
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
|
||||
} else {
|
||||
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
|
||||
}
|
||||
} else {
|
||||
super.setFloatValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObjectValues(Object... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
if (mProperty != null) {
|
||||
setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator) null, values));
|
||||
} else {
|
||||
setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator) null, values));
|
||||
}
|
||||
} else {
|
||||
super.setObjectValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (DBG) {
|
||||
Logger.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
|
||||
for (int i = 0; i < mValues.length; ++i) {
|
||||
PropertyValuesHolder pvh = mValues[i];
|
||||
ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
|
||||
Logger.d("ObjectAnimator", " Values[" + i + "]: " +
|
||||
pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " +
|
||||
keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue());
|
||||
}
|
||||
}
|
||||
super.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called immediately before processing the first animation
|
||||
* frame of an animation. If there is a nonzero <code>startDelay</code>, the
|
||||
* function is called after that delay ends.
|
||||
* It takes care of the final initialization steps for the
|
||||
* animation. This includes setting mEvaluator, if the user has not yet
|
||||
* set it up, and the setter/getter methods, if the user did not supply
|
||||
* them.
|
||||
* <p>
|
||||
* <p>Overriders of this method should call the superclass method to cause
|
||||
* internal mechanisms to be set up correctly.</p>
|
||||
*/
|
||||
@Override
|
||||
void initAnimation() {
|
||||
if (!mInitialized) {
|
||||
// mValueType may change due to setter/getter setup; do this before calling super.init(),
|
||||
// which uses mValueType to set up the default type evaluator.
|
||||
if ((mProperty == null) && AnimatorProxy.NEEDS_PROXY && (mTarget instanceof View) && PROXY_PROPERTIES.containsKey(mPropertyName)) {
|
||||
setProperty(PROXY_PROPERTIES.get(mPropertyName));
|
||||
}
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupSetterAndGetter(mTarget);
|
||||
}
|
||||
super.initAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the animation. The default duration is 300 milliseconds.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
* @return ObjectAnimator The object called with setDuration(). This return
|
||||
* value makes it easier to compose statements together that construct and then set the
|
||||
* duration, as in
|
||||
* <code>ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start()</code>.
|
||||
*/
|
||||
@Override
|
||||
public ObjectAnimator setDuration(long duration) {
|
||||
super.setDuration(duration);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The target object whose property will be animated by this animation
|
||||
*
|
||||
* @return The object being animated
|
||||
*/
|
||||
public Object getTarget() {
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target object whose property will be animated by this animation
|
||||
*
|
||||
* @param target The object being animated
|
||||
*/
|
||||
@Override
|
||||
public void setTarget(Object target) {
|
||||
if (mTarget != target) {
|
||||
final Object oldTarget = mTarget;
|
||||
mTarget = target;
|
||||
if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
|
||||
return;
|
||||
}
|
||||
// New target type should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupStartValues() {
|
||||
initAnimation();
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupStartValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupEndValues() {
|
||||
initAnimation();
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupEndValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called with the elapsed fraction of the animation during every
|
||||
* animation frame. This function turns the elapsed fraction into an interpolated fraction
|
||||
* and then into an animated value (from the evaluator. The function is called mostly during
|
||||
* animation updates, but it is also called when the <code>end()</code>
|
||||
* function is called, to set the final value on the property.
|
||||
* <p>
|
||||
* <p>Overrides of this method must call the superclass to perform the calculation
|
||||
* of the animated value.</p>
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation.
|
||||
*/
|
||||
@Override
|
||||
void animateValue(float fraction) {
|
||||
super.animateValue(fraction);
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setAnimatedValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectAnimator clone() {
|
||||
final ObjectAnimator anim = (ObjectAnimator) super.clone();
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " +
|
||||
mTarget;
|
||||
if (mValues != null) {
|
||||
for (int i = 0; i < mValues.length; ++i) {
|
||||
returnVal += "\n " + mValues[i].toString();
|
||||
}
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.adins.libs.nineoldandroids.util.FloatProperty;
|
||||
import com.adins.libs.nineoldandroids.util.IntProperty;
|
||||
import com.adins.libs.nineoldandroids.util.Property;
|
||||
import com.adins.libs.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
final class PreHoneycombCompat {
|
||||
static Property<View, Float> ALPHA = new FloatProperty<View>("alpha") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setAlpha(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getAlpha();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> PIVOT_X = new FloatProperty<View>("pivotX") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setPivotX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getPivotX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> PIVOT_Y = new FloatProperty<View>("pivotY") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setPivotY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getPivotY();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setTranslationX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getTranslationX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setTranslationY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getTranslationY();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> ROTATION = new FloatProperty<View>("rotation") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setRotation(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getRotation();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setRotationX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getRotationX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setRotationY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getRotationY();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setScaleX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getScaleX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setScaleY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getScaleY();
|
||||
}
|
||||
};
|
||||
static Property<View, Integer> SCROLL_X = new IntProperty<View>("scrollX") {
|
||||
@Override
|
||||
public void setValue(View object, int value) {
|
||||
AnimatorProxy.wrap(object).setScrollX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(View object) {
|
||||
return AnimatorProxy.wrap(object).getScrollX();
|
||||
}
|
||||
};
|
||||
static Property<View, Integer> SCROLL_Y = new IntProperty<View>("scrollY") {
|
||||
@Override
|
||||
public void setValue(View object, int value) {
|
||||
AnimatorProxy.wrap(object).setScrollY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(View object) {
|
||||
return AnimatorProxy.wrap(object).getScrollY();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> X = new FloatProperty<View>("x") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> Y = new FloatProperty<View>("y") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getY();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//No instances
|
||||
private PreHoneycombCompat() {
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,78 @@
|
|||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This class provides a simple callback mechanism to listeners that is synchronized with other
|
||||
* animators in the system. There is no duration, interpolation, or object value-setting
|
||||
* with this Animator. Instead, it is simply started and proceeds to send out events on every
|
||||
* animation frame to its TimeListener (if set), with information about this animator,
|
||||
* the total elapsed time, and the time since the last animation frame.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class TimeAnimator extends ValueAnimator {
|
||||
|
||||
private TimeListener mListener;
|
||||
private long mPreviousTime = -1;
|
||||
|
||||
@Override
|
||||
boolean animationFrame(long currentTime) {
|
||||
if (mPlayingState == STOPPED) {
|
||||
mPlayingState = RUNNING;
|
||||
if (mSeekTime < 0) {
|
||||
mStartTime = currentTime;
|
||||
} else {
|
||||
mStartTime = currentTime - mSeekTime;
|
||||
// Now that we're playing, reset the seek time
|
||||
mSeekTime = -1;
|
||||
}
|
||||
}
|
||||
if (mListener != null) {
|
||||
long totalTime = currentTime - mStartTime;
|
||||
long deltaTime = (mPreviousTime < 0) ? 0 : (currentTime - mPreviousTime);
|
||||
mPreviousTime = currentTime;
|
||||
mListener.onTimeUpdate(this, totalTime, deltaTime);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener that is sent update events throughout the life of
|
||||
* an animation.
|
||||
*
|
||||
* @param listener the listener to be set.
|
||||
*/
|
||||
public void setTimeListener(TimeListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
void animateValue(float fraction) {
|
||||
// Noop
|
||||
}
|
||||
|
||||
@Override
|
||||
void initAnimation() {
|
||||
// noop
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementors of this interface can set themselves as update listeners
|
||||
* to a <code>TimeAnimator</code> instance to receive callbacks on every animation
|
||||
* frame to receive the total time since the animator started and the delta time
|
||||
* since the last frame. The first time the listener is called, totalTime and
|
||||
* deltaTime should both be zero.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static interface TimeListener {
|
||||
/**
|
||||
* <p>Notifies listeners of the occurrence of another frame of the animation,
|
||||
* along with information about the elapsed time.</p>
|
||||
*
|
||||
* @param animation The animator sending out the notification.
|
||||
* @param totalTime The
|
||||
*/
|
||||
void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators
|
||||
* allow developers to create animations on arbitrary property types, by allowing them to supply
|
||||
* custom evaulators for types that are not automatically understood and used by the animation
|
||||
* system.
|
||||
*
|
||||
* @see ValueAnimator#setEvaluator(TypeEvaluator)
|
||||
*/
|
||||
public interface TypeEvaluator<T> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value.
|
||||
* @param endValue The end value.
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public T evaluate(float fraction, T startValue, T endValue);
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.adins.libs.nineoldandroids.util;
|
||||
|
||||
/**
|
||||
* An implementation of {@link android.util.Property} to be used specifically with fields of type
|
||||
* <code>float</code>. This type-specific subclass enables performance benefit by allowing
|
||||
* calls to a {@link #set(Object, Float) set()} function that takes the primitive
|
||||
* <code>float</code> type and avoids autoboxing and other overhead associated with the
|
||||
* <code>Float</code> class.
|
||||
*
|
||||
* @param <T> The class on which the Property is declared.
|
||||
* @hide
|
||||
*/
|
||||
public abstract class FloatProperty<T> extends Property<T, Float> {
|
||||
|
||||
public FloatProperty(String name) {
|
||||
super(Float.class, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
|
||||
* with fields of type <code>float</code>.
|
||||
*/
|
||||
public abstract void setValue(T object, float value);
|
||||
|
||||
@Override
|
||||
final public void set(T object, Float value) {
|
||||
setValue(object, value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.adins.libs.nineoldandroids.util;
|
||||
|
||||
/**
|
||||
* An implementation of {@link android.util.Property} to be used specifically with fields of type
|
||||
* <code>int</code>. This type-specific subclass enables performance benefit by allowing
|
||||
* calls to a {@link #set(Object, Integer) set()} function that takes the primitive
|
||||
* <code>int</code> type and avoids autoboxing and other overhead associated with the
|
||||
* <code>Integer</code> class.
|
||||
*
|
||||
* @param <T> The class on which the Property is declared.
|
||||
* @hide
|
||||
*/
|
||||
public abstract class IntProperty<T> extends Property<T, Integer> {
|
||||
|
||||
public IntProperty(String name) {
|
||||
super(Integer.class, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing
|
||||
* with fields of type <code>int</code>.
|
||||
*/
|
||||
public abstract void setValue(T object, int value);
|
||||
|
||||
@Override
|
||||
final public void set(T object, Integer value) {
|
||||
set(object, value.intValue());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.adins.libs.nineoldandroids.util;
|
||||
|
||||
/**
|
||||
* Thrown when code requests a {@link Property} on a class that does
|
||||
* not expose the appropriate method or field.
|
||||
*
|
||||
* @see Property#of(java.lang.Class, java.lang.Class, java.lang.String)
|
||||
*/
|
||||
public class NoSuchPropertyException extends RuntimeException {
|
||||
|
||||
public NoSuchPropertyException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.adins.libs.nineoldandroids.util;
|
||||
|
||||
|
||||
/**
|
||||
* A property is an abstraction that can be used to represent a <emb>mutable</em> value that is held
|
||||
* in a <em>host</em> object. The Property's {@link #set(Object, Object)} or {@link #get(Object)}
|
||||
* methods can be implemented in terms of the private fields of the host object, or via "setter" and
|
||||
* "getter" methods or by some other mechanism, as appropriate.
|
||||
*
|
||||
* @param <T> The class on which the property is declared.
|
||||
* @param <V> The type that this property represents.
|
||||
*/
|
||||
public abstract class Property<T, V> {
|
||||
|
||||
private final String mName;
|
||||
private final Class<V> mType;
|
||||
|
||||
/**
|
||||
* A constructor that takes an identifying name and {@link #getType() type} for the property.
|
||||
*/
|
||||
public Property(Class<V> type, String name) {
|
||||
mName = name;
|
||||
mType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* This factory method creates and returns a Property given the <code>class</code> and
|
||||
* <code>name</code> parameters, where the <code>"name"</code> parameter represents either:
|
||||
* <ul>
|
||||
* <li>a public <code>getName()</code> method on the class which takes no arguments, plus an
|
||||
* optional public <code>setName()</code> method which takes a value of the same type
|
||||
* returned by <code>getName()</code>
|
||||
* <li>a public <code>isName()</code> method on the class which takes no arguments, plus an
|
||||
* optional public <code>setName()</code> method which takes a value of the same type
|
||||
* returned by <code>isName()</code>
|
||||
* <li>a public <code>name</code> field on the class
|
||||
* </ul>
|
||||
* <p>
|
||||
* <p>If either of the get/is method alternatives is found on the class, but an appropriate
|
||||
* <code>setName()</code> method is not found, the <code>Property</code> will be
|
||||
* {@link #isReadOnly() readOnly}. Calling the {@link #set(Object, Object)} method on such
|
||||
* a property is allowed, but will have no effect.</p>
|
||||
* <p>
|
||||
* <p>If neither the methods nor the field are found on the class a
|
||||
* {@link NoSuchPropertyException} exception will be thrown.</p>
|
||||
*/
|
||||
public static <T, V> Property<T, V> of(Class<T> hostType, Class<V> valueType, String name) {
|
||||
return new ReflectiveProperty<T, V>(hostType, valueType, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the {@link #set(Object, Object)} method does not set the value on the target
|
||||
* object (in which case the {@link #set(Object, Object) set()} method should throw a {@link
|
||||
* NoSuchPropertyException} exception). This may happen if the Property wraps functionality that
|
||||
* allows querying the underlying value but not setting it. For example, the {@link #of(Class,
|
||||
* Class, String)} factory method may return a Property with name "foo" for an object that has
|
||||
* only a <code>getFoo()</code> or <code>isFoo()</code> method, but no matching
|
||||
* <code>setFoo()</code> method.
|
||||
*/
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value on <code>object</code> which this property represents. If the method is unable
|
||||
* to set the value on the target object it will throw an {@link UnsupportedOperationException}
|
||||
* exception.
|
||||
*/
|
||||
public void set(T object, V value) {
|
||||
throw new UnsupportedOperationException("Property " + getName() + " is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value that this property represents on the given <code>object</code>.
|
||||
*/
|
||||
public abstract V get(T object);
|
||||
|
||||
/**
|
||||
* Returns the name for this property.
|
||||
*/
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type for this property.
|
||||
*/
|
||||
public Class<V> getType() {
|
||||
return mType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.adins.libs.nineoldandroids.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Internal class to automatically generate a Property for a given class/name pair, given the
|
||||
* specification of {@link Property#of(java.lang.Class, java.lang.Class, java.lang.String)}
|
||||
*/
|
||||
class ReflectiveProperty<T, V> extends Property<T, V> {
|
||||
|
||||
private static final String PREFIX_GET = "get";
|
||||
private static final String PREFIX_IS = "is";
|
||||
private static final String PREFIX_SET = "set";
|
||||
private Method mSetter;
|
||||
private Method mGetter;
|
||||
private Field mField;
|
||||
|
||||
/**
|
||||
* For given property name 'name', look for getName/isName method or 'name' field.
|
||||
* Also look for setName method (optional - could be readonly). Failing method getters and
|
||||
* field results in throwing NoSuchPropertyException.
|
||||
*
|
||||
* @param propertyHolder The class on which the methods or field are found
|
||||
* @param name The name of the property, where this name is capitalized and appended to
|
||||
* "get" and "is to search for the appropriate methods. If the get/is methods are not found,
|
||||
* the constructor will search for a field with that exact name.
|
||||
*/
|
||||
public ReflectiveProperty(Class<T> propertyHolder, Class<V> valueType, String name) {
|
||||
// TODO: cache reflection info for each new class/name pair
|
||||
super(valueType, name);
|
||||
char firstLetter = Character.toUpperCase(name.charAt(0));
|
||||
String theRest = name.substring(1);
|
||||
String capitalizedName = firstLetter + theRest;
|
||||
String getterName = PREFIX_GET + capitalizedName;
|
||||
try {
|
||||
mGetter = propertyHolder.getMethod(getterName, (Class<?>[]) null);
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
/* The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||
* getDeclaredMethod(..) does not find superclass methods, so it's implemented as a fallback.
|
||||
*/
|
||||
mGetter = propertyHolder.getDeclaredMethod(getterName, (Class<?>[]) null);
|
||||
mGetter.setAccessible(true);
|
||||
} catch (NoSuchMethodException e2) {
|
||||
// getName() not available - try isName() instead
|
||||
getterName = PREFIX_IS + capitalizedName;
|
||||
try {
|
||||
mGetter = propertyHolder.getMethod(getterName, (Class<?>[]) null);
|
||||
} catch (NoSuchMethodException e3) {
|
||||
try {
|
||||
/* The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||
* getDeclaredMethod(..) does not find superclass methods, so it's implemented as a fallback.
|
||||
*/
|
||||
mGetter = propertyHolder.getDeclaredMethod(getterName, (Class<?>[]) null);
|
||||
mGetter.setAccessible(true);
|
||||
} catch (NoSuchMethodException e4) {
|
||||
// Try public field instead
|
||||
try {
|
||||
mField = propertyHolder.getField(name);
|
||||
Class fieldType = mField.getType();
|
||||
if (!typesMatch(valueType, fieldType)) {
|
||||
throw new NoSuchPropertyException("Underlying type (" + fieldType + ") " +
|
||||
"does not match Property type (" + valueType + ")");
|
||||
}
|
||||
return;
|
||||
} catch (NoSuchFieldException e5) {
|
||||
// no way to access property - throw appropriate exception
|
||||
throw new NoSuchPropertyException("No accessor method or field found for"
|
||||
+ " property with name " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Class getterType = mGetter.getReturnType();
|
||||
// Check to make sure our getter type matches our valueType
|
||||
if (!typesMatch(valueType, getterType)) {
|
||||
throw new NoSuchPropertyException("Underlying type (" + getterType + ") " +
|
||||
"does not match Property type (" + valueType + ")");
|
||||
}
|
||||
String setterName = PREFIX_SET + capitalizedName;
|
||||
try {
|
||||
// mSetter = propertyHolder.getMethod(setterName, getterType);
|
||||
// The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||
mSetter = propertyHolder.getDeclaredMethod(setterName, getterType);
|
||||
mSetter.setAccessible(true);
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
// Okay to not have a setter - just a readonly property
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to check whether the type of the underlying field/method on the target
|
||||
* object matches the type of the Property. The extra checks for primitive types are because
|
||||
* generics will force the Property type to be a class, whereas the type of the underlying
|
||||
* method/field will probably be a primitive type instead. Accept float as matching Float,
|
||||
* etc.
|
||||
*/
|
||||
private boolean typesMatch(Class<V> valueType, Class getterType) {
|
||||
if (getterType != valueType) {
|
||||
if (getterType.isPrimitive()) {
|
||||
return (getterType == float.class && valueType == Float.class) ||
|
||||
(getterType == int.class && valueType == Integer.class) ||
|
||||
(getterType == boolean.class && valueType == Boolean.class) ||
|
||||
(getterType == long.class && valueType == Long.class) ||
|
||||
(getterType == double.class && valueType == Double.class) ||
|
||||
(getterType == short.class && valueType == Short.class) ||
|
||||
(getterType == byte.class && valueType == Byte.class) ||
|
||||
(getterType == char.class && valueType == Character.class);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T object, V value) {
|
||||
if (mSetter != null) {
|
||||
try {
|
||||
mSetter.invoke(object, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
} else if (mField != null) {
|
||||
try {
|
||||
mField.set(object, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Property " + getName() + " is read-only");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(T object) {
|
||||
if (mGetter != null) {
|
||||
try {
|
||||
return (V) mGetter.invoke(object, (Object[]) null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
} else if (mField != null) {
|
||||
try {
|
||||
return (V) mField.get(object);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
// Should not get here: there should always be a non-null getter or field
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if there is no setter or public field underlying this Property.
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return (mSetter == null && mField == null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
package com.adins.libs.nineoldandroids.view;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import static com.adins.libs.nineoldandroids.view.animation.AnimatorProxy.NEEDS_PROXY;
|
||||
import static com.adins.libs.nineoldandroids.view.animation.AnimatorProxy.wrap;
|
||||
|
||||
public final class ViewHelper {
|
||||
private ViewHelper() {
|
||||
}
|
||||
|
||||
public static float getAlpha(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getAlpha() : Honeycomb.getAlpha(view);
|
||||
}
|
||||
|
||||
public static void setAlpha(View view, float alpha) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setAlpha(alpha);
|
||||
} else {
|
||||
Honeycomb.setAlpha(view, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getPivotX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getPivotX() : Honeycomb.getPivotX(view);
|
||||
}
|
||||
|
||||
public static void setPivotX(View view, float pivotX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setPivotX(pivotX);
|
||||
} else {
|
||||
Honeycomb.setPivotX(view, pivotX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getPivotY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getPivotY() : Honeycomb.getPivotY(view);
|
||||
}
|
||||
|
||||
public static void setPivotY(View view, float pivotY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setPivotY(pivotY);
|
||||
} else {
|
||||
Honeycomb.setPivotY(view, pivotY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getRotation(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getRotation() : Honeycomb.getRotation(view);
|
||||
}
|
||||
|
||||
public static void setRotation(View view, float rotation) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setRotation(rotation);
|
||||
} else {
|
||||
Honeycomb.setRotation(view, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getRotationX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getRotationX() : Honeycomb.getRotationX(view);
|
||||
}
|
||||
|
||||
public static void setRotationX(View view, float rotationX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setRotationX(rotationX);
|
||||
} else {
|
||||
Honeycomb.setRotationX(view, rotationX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getRotationY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getRotationY() : Honeycomb.getRotationY(view);
|
||||
}
|
||||
|
||||
public static void setRotationY(View view, float rotationY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setRotationY(rotationY);
|
||||
} else {
|
||||
Honeycomb.setRotationY(view, rotationY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getScaleX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getScaleX() : Honeycomb.getScaleX(view);
|
||||
}
|
||||
|
||||
public static void setScaleX(View view, float scaleX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setScaleX(scaleX);
|
||||
} else {
|
||||
Honeycomb.setScaleX(view, scaleX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getScaleY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getScaleY() : Honeycomb.getScaleY(view);
|
||||
}
|
||||
|
||||
public static void setScaleY(View view, float scaleY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setScaleY(scaleY);
|
||||
} else {
|
||||
Honeycomb.setScaleY(view, scaleY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getScrollX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getScrollX() : Honeycomb.getScrollX(view);
|
||||
}
|
||||
|
||||
public static void setScrollX(View view, int scrollX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setScrollX(scrollX);
|
||||
} else {
|
||||
Honeycomb.setScrollX(view, scrollX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getScrollY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getScrollY() : Honeycomb.getScrollY(view);
|
||||
}
|
||||
|
||||
public static void setScrollY(View view, int scrollY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setScrollY(scrollY);
|
||||
} else {
|
||||
Honeycomb.setScrollY(view, scrollY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getTranslationX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getTranslationX() : Honeycomb.getTranslationX(view);
|
||||
}
|
||||
|
||||
public static void setTranslationX(View view, float translationX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setTranslationX(translationX);
|
||||
} else {
|
||||
Honeycomb.setTranslationX(view, translationX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getTranslationY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getTranslationY() : Honeycomb.getTranslationY(view);
|
||||
}
|
||||
|
||||
public static void setTranslationY(View view, float translationY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setTranslationY(translationY);
|
||||
} else {
|
||||
Honeycomb.setTranslationY(view, translationY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getX() : Honeycomb.getX(view);
|
||||
}
|
||||
|
||||
public static void setX(View view, float x) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setX(x);
|
||||
} else {
|
||||
Honeycomb.setX(view, x);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getY() : Honeycomb.getY(view);
|
||||
}
|
||||
|
||||
public static void setY(View view, float y) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setY(y);
|
||||
} else {
|
||||
Honeycomb.setY(view, y);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Honeycomb {
|
||||
static float getAlpha(View view) {
|
||||
return view.getAlpha();
|
||||
}
|
||||
|
||||
static void setAlpha(View view, float alpha) {
|
||||
view.setAlpha(alpha);
|
||||
}
|
||||
|
||||
static float getPivotX(View view) {
|
||||
return view.getPivotX();
|
||||
}
|
||||
|
||||
static void setPivotX(View view, float pivotX) {
|
||||
view.setPivotX(pivotX);
|
||||
}
|
||||
|
||||
static float getPivotY(View view) {
|
||||
return view.getPivotY();
|
||||
}
|
||||
|
||||
static void setPivotY(View view, float pivotY) {
|
||||
view.setPivotY(pivotY);
|
||||
}
|
||||
|
||||
static float getRotation(View view) {
|
||||
return view.getRotation();
|
||||
}
|
||||
|
||||
static void setRotation(View view, float rotation) {
|
||||
view.setRotation(rotation);
|
||||
}
|
||||
|
||||
static float getRotationX(View view) {
|
||||
return view.getRotationX();
|
||||
}
|
||||
|
||||
static void setRotationX(View view, float rotationX) {
|
||||
view.setRotationX(rotationX);
|
||||
}
|
||||
|
||||
static float getRotationY(View view) {
|
||||
return view.getRotationY();
|
||||
}
|
||||
|
||||
static void setRotationY(View view, float rotationY) {
|
||||
view.setRotationY(rotationY);
|
||||
}
|
||||
|
||||
static float getScaleX(View view) {
|
||||
return view.getScaleX();
|
||||
}
|
||||
|
||||
static void setScaleX(View view, float scaleX) {
|
||||
view.setScaleX(scaleX);
|
||||
}
|
||||
|
||||
static float getScaleY(View view) {
|
||||
return view.getScaleY();
|
||||
}
|
||||
|
||||
static void setScaleY(View view, float scaleY) {
|
||||
view.setScaleY(scaleY);
|
||||
}
|
||||
|
||||
static float getScrollX(View view) {
|
||||
return view.getScrollX();
|
||||
}
|
||||
|
||||
static void setScrollX(View view, int scrollX) {
|
||||
view.setScrollX(scrollX);
|
||||
}
|
||||
|
||||
static float getScrollY(View view) {
|
||||
return view.getScrollY();
|
||||
}
|
||||
|
||||
static void setScrollY(View view, int scrollY) {
|
||||
view.setScrollY(scrollY);
|
||||
}
|
||||
|
||||
static float getTranslationX(View view) {
|
||||
return view.getTranslationX();
|
||||
}
|
||||
|
||||
static void setTranslationX(View view, float translationX) {
|
||||
view.setTranslationX(translationX);
|
||||
}
|
||||
|
||||
static float getTranslationY(View view) {
|
||||
return view.getTranslationY();
|
||||
}
|
||||
|
||||
static void setTranslationY(View view, float translationY) {
|
||||
view.setTranslationY(translationY);
|
||||
}
|
||||
|
||||
static float getX(View view) {
|
||||
return view.getX();
|
||||
}
|
||||
|
||||
static void setX(View view, float x) {
|
||||
view.setX(x);
|
||||
}
|
||||
|
||||
static float getY(View view) {
|
||||
return view.getY();
|
||||
}
|
||||
|
||||
static void setY(View view, float y) {
|
||||
view.setY(y);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.view;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.adins.libs.nineoldandroids.animation.Animator;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* This class enables automatic and optimized animation of select properties on View objects.
|
||||
* If only one or two properties on a View object are being animated, then using an
|
||||
* {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
|
||||
* are well equipped to do the right thing to set the property and invalidate the view
|
||||
* appropriately. But if several properties are animated simultaneously, or if you just want a
|
||||
* more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
|
||||
* more well-suited to the task.
|
||||
* <p>
|
||||
* <p>This class may provide better performance for several simultaneous animations, because
|
||||
* it will optimize invalidate calls to take place only once for several properties instead of each
|
||||
* animated property independently causing its own invalidation. Also, the syntax of using this
|
||||
* class could be easier to use because the caller need only tell the View object which
|
||||
* property to animate, and the value to animate either to or by, and this class handles the
|
||||
* details of configuring the underlying Animator class and starting it.</p>
|
||||
* <p>
|
||||
* <p>This class is not constructed by the caller, but rather by the View whose properties
|
||||
* it will animate. Calls to {@link android.view.View#animate()} will return a reference
|
||||
* to the appropriate ViewPropertyAnimator object for that View.</p>
|
||||
*/
|
||||
public abstract class ViewPropertyAnimator {
|
||||
private static final WeakHashMap<View, ViewPropertyAnimator> ANIMATORS =
|
||||
new WeakHashMap<View, ViewPropertyAnimator>(0);
|
||||
|
||||
/**
|
||||
* This method returns a ViewPropertyAnimator object, which can be used to animate specific
|
||||
* properties on this View.
|
||||
*
|
||||
* @param view View to animate.
|
||||
* @return The ViewPropertyAnimator associated with this View.
|
||||
*/
|
||||
public static ViewPropertyAnimator animate(View view) {
|
||||
ViewPropertyAnimator animator = ANIMATORS.get(view);
|
||||
if (animator == null) {
|
||||
final int version = Build.VERSION.SDK_INT;
|
||||
if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
animator = new ViewPropertyAnimatorICS(view);
|
||||
} else if (version >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
animator = new ViewPropertyAnimatorHC(view);
|
||||
} else {
|
||||
animator = new ViewPropertyAnimatorPreHC(view);
|
||||
}
|
||||
ANIMATORS.put(view, animator);
|
||||
}
|
||||
return animator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current duration of property animations. If the duration was set on this
|
||||
* object, that value is returned. Otherwise, the default value of the underlying Animator
|
||||
* is returned.
|
||||
*
|
||||
* @return The duration of animations, in milliseconds.
|
||||
* @see #setDuration(long)
|
||||
*/
|
||||
public abstract long getDuration();
|
||||
|
||||
/**
|
||||
* Sets the duration for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default value for ValueAnimator. Calling this method
|
||||
* will cause the declared value to be used instead.
|
||||
*
|
||||
* @param duration The length of ensuing property animations, in milliseconds. The value
|
||||
* cannot be negative.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator setDuration(long duration);
|
||||
|
||||
/**
|
||||
* Returns the current startDelay of property animations. If the startDelay was set on this
|
||||
* object, that value is returned. Otherwise, the default value of the underlying Animator
|
||||
* is returned.
|
||||
*
|
||||
* @return The startDelay of animations, in milliseconds.
|
||||
* @see #setStartDelay(long)
|
||||
*/
|
||||
public abstract long getStartDelay();
|
||||
|
||||
/**
|
||||
* Sets the startDelay for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default value for ValueAnimator. Calling this method
|
||||
* will cause the declared value to be used instead.
|
||||
*
|
||||
* @param startDelay The delay of ensuing property animations, in milliseconds. The value
|
||||
* cannot be negative.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator setStartDelay(long startDelay);
|
||||
|
||||
/**
|
||||
* Sets the interpolator for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default interpolator for ValueAnimator. Calling this method
|
||||
* will cause the declared object to be used instead.
|
||||
*
|
||||
* @param interpolator The TimeInterpolator to be used for ensuing property animations.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator setInterpolator(/*Time*/Interpolator interpolator);
|
||||
|
||||
/**
|
||||
* Sets a listener for events in the underlying Animators that run the property
|
||||
* animations.
|
||||
*
|
||||
* @param listener The listener to be called with AnimatorListener events.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator setListener(Animator.AnimatorListener listener);
|
||||
|
||||
/**
|
||||
* Starts the currently pending property animations immediately. Calling <code>start()</code>
|
||||
* is optional because all animations start automatically at the next opportunity. However,
|
||||
* if the animations are needed to start immediately and synchronously (not at the time when
|
||||
* the next event is processed by the hierarchy, which is when the animations would begin
|
||||
* otherwise), then this method can be used.
|
||||
*/
|
||||
public abstract void start();
|
||||
|
||||
/**
|
||||
* Cancels all property animations that are currently running or pending.
|
||||
*/
|
||||
public abstract void cancel();
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>x</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setX(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator x(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>x</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setX(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator xBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>y</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setY(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator y(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>y</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setY(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator yBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotation</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setRotation(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotation(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotation</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setRotation(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotationX</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setRotationX(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationX(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotationX</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setRotationX(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationXBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotationY</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setRotationY(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationY(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotationY</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setRotationY(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationYBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>translationX</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setTranslationX(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator translationX(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>translationX</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setTranslationX(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator translationXBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>translationY</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setTranslationY(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator translationY(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>translationY</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setTranslationY(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator translationYBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>scaleX</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setScaleX(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator scaleX(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>scaleX</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setScaleX(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator scaleXBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>scaleY</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setScaleY(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator scaleY(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>scaleY</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setScaleY(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator scaleYBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>alpha</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setAlpha(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator alpha(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>alpha</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
* @see View#setAlpha(float)
|
||||
*/
|
||||
public abstract ViewPropertyAnimator alphaBy(float value);
|
||||
}
|
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.view;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.adins.libs.nineoldandroids.animation.Animator;
|
||||
import com.adins.libs.nineoldandroids.animation.ValueAnimator;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
class ViewPropertyAnimatorHC extends ViewPropertyAnimator {
|
||||
|
||||
/**
|
||||
* Constants used to associate a property being requested and the mechanism used to set
|
||||
* the property (this class calls directly into View to set the properties in question).
|
||||
*/
|
||||
private static final int NONE = 0x0000;
|
||||
private static final int TRANSLATION_X = 0x0001;
|
||||
private static final int TRANSLATION_Y = 0x0002;
|
||||
private static final int SCALE_X = 0x0004;
|
||||
private static final int SCALE_Y = 0x0008;
|
||||
private static final int ROTATION = 0x0010;
|
||||
private static final int ROTATION_X = 0x0020;
|
||||
private static final int ROTATION_Y = 0x0040;
|
||||
private static final int X = 0x0080;
|
||||
private static final int Y = 0x0100;
|
||||
private static final int ALPHA = 0x0200;
|
||||
private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
|
||||
ROTATION | ROTATION_X | ROTATION_Y | X | Y;
|
||||
/**
|
||||
* A WeakReference holding the View whose properties are being animated by this class.
|
||||
* This is set at construction time.
|
||||
*/
|
||||
private final WeakReference<View> mView;
|
||||
/**
|
||||
* This list holds the properties that have been asked to animate. We allow the caller to
|
||||
* request several animations prior to actually starting the underlying animator. This
|
||||
* enables us to run one single animator to handle several properties in parallel. Each
|
||||
* property is tossed onto the pending list until the animation actually starts (which is
|
||||
* done by posting it onto mView), at which time the pending list is cleared and the properties
|
||||
* on that list are added to the list of properties associated with that animator.
|
||||
*/
|
||||
ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
|
||||
/**
|
||||
* The duration of the underlying Animator object. By default, we don't set the duration
|
||||
* on the Animator and just use its default duration. If the duration is ever set on this
|
||||
* Animator, then we use the duration that it was set to.
|
||||
*/
|
||||
private long mDuration;
|
||||
/**
|
||||
* A flag indicating whether the duration has been set on this object. If not, we don't set
|
||||
* the duration on the underlying Animator, but instead just use its default duration.
|
||||
*/
|
||||
private boolean mDurationSet = false;
|
||||
/**
|
||||
* The startDelay of the underlying Animator object. By default, we don't set the startDelay
|
||||
* on the Animator and just use its default startDelay. If the startDelay is ever set on this
|
||||
* Animator, then we use the startDelay that it was set to.
|
||||
*/
|
||||
private long mStartDelay = 0;
|
||||
/**
|
||||
* A flag indicating whether the startDelay has been set on this object. If not, we don't set
|
||||
* the startDelay on the underlying Animator, but instead just use its default startDelay.
|
||||
*/
|
||||
private boolean mStartDelaySet = false;
|
||||
/**
|
||||
* The interpolator of the underlying Animator object. By default, we don't set the interpolator
|
||||
* on the Animator and just use its default interpolator. If the interpolator is ever set on
|
||||
* this Animator, then we use the interpolator that it was set to.
|
||||
*/
|
||||
private /*Time*/ Interpolator mInterpolator;
|
||||
/**
|
||||
* A flag indicating whether the interpolator has been set on this object. If not, we don't set
|
||||
* the interpolator on the underlying Animator, but instead just use its default interpolator.
|
||||
*/
|
||||
private boolean mInterpolatorSet = false;
|
||||
/**
|
||||
* Listener for the lifecycle events of the underlying
|
||||
*/
|
||||
private Animator.AnimatorListener mListener = null;
|
||||
/**
|
||||
* This listener is the mechanism by which the underlying Animator causes changes to the
|
||||
* properties currently being animated, as well as the cleanup after an animation is
|
||||
* complete.
|
||||
*/
|
||||
private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
|
||||
/**
|
||||
* This list tracks the list of properties being animated by any particular animator.
|
||||
* In most situations, there would only ever be one animator running at a time. But it is
|
||||
* possible to request some properties to animate together, then while those properties
|
||||
* are animating, to request some other properties to animate together. The way that
|
||||
* works is by having this map associate the group of properties being animated with the
|
||||
* animator handling the animation. On every update event for an Animator, we ask the
|
||||
* map for the associated properties and set them accordingly.
|
||||
*/
|
||||
private HashMap<Animator, PropertyBundle> mAnimatorMap =
|
||||
new HashMap<Animator, PropertyBundle>();
|
||||
/**
|
||||
* The mechanism by which the user can request several properties that are then animated
|
||||
* together works by posting this Runnable to start the underlying Animator. Every time
|
||||
* a property animation is requested, we cancel any previous postings of the Runnable
|
||||
* and re-post it. This means that we will only ever run the Runnable (and thus start the
|
||||
* underlying animator) after the caller is done setting the properties that should be
|
||||
* animated together.
|
||||
*/
|
||||
private Runnable mAnimationStarter = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startAnimation();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor, called by View. This is private by design, as the user should only
|
||||
* get a ViewPropertyAnimator by calling View.animate().
|
||||
*
|
||||
* @param view The View associated with this ViewPropertyAnimator
|
||||
*/
|
||||
ViewPropertyAnimatorHC(View view) {
|
||||
mView = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default value for ValueAnimator. Calling this method
|
||||
* will cause the declared value to be used instead.
|
||||
*
|
||||
* @param duration The length of ensuing property animations, in milliseconds. The value
|
||||
* cannot be negative.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public ViewPropertyAnimator setDuration(long duration) {
|
||||
if (duration < 0) {
|
||||
throw new IllegalArgumentException("Animators cannot have negative duration: " +
|
||||
duration);
|
||||
}
|
||||
mDurationSet = true;
|
||||
mDuration = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current duration of property animations. If the duration was set on this
|
||||
* object, that value is returned. Otherwise, the default value of the underlying Animator
|
||||
* is returned.
|
||||
*
|
||||
* @return The duration of animations, in milliseconds.
|
||||
* @see #setDuration(long)
|
||||
*/
|
||||
public long getDuration() {
|
||||
if (mDurationSet) {
|
||||
return mDuration;
|
||||
} else {
|
||||
// Just return the default from ValueAnimator, since that's what we'd get if
|
||||
// the value has not been set otherwise
|
||||
return new ValueAnimator().getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartDelay() {
|
||||
if (mStartDelaySet) {
|
||||
return mStartDelay;
|
||||
} else {
|
||||
// Just return the default from ValueAnimator (0), since that's what we'd get if
|
||||
// the value has not been set otherwise
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setStartDelay(long startDelay) {
|
||||
if (startDelay < 0) {
|
||||
throw new IllegalArgumentException("Animators cannot have negative duration: " +
|
||||
startDelay);
|
||||
}
|
||||
mStartDelaySet = true;
|
||||
mStartDelay = startDelay;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setInterpolator(/*Time*/Interpolator interpolator) {
|
||||
mInterpolatorSet = true;
|
||||
mInterpolator = interpolator;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
|
||||
mListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (mAnimatorMap.size() > 0) {
|
||||
HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
|
||||
(HashMap<Animator, PropertyBundle>) mAnimatorMap.clone();
|
||||
Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
|
||||
for (Animator runningAnim : animatorSet) {
|
||||
runningAnim.cancel();
|
||||
}
|
||||
}
|
||||
mPendingAnimations.clear();
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.removeCallbacks(mAnimationStarter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator x(float value) {
|
||||
animateProperty(X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator xBy(float value) {
|
||||
animatePropertyBy(X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator y(float value) {
|
||||
animateProperty(Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator yBy(float value) {
|
||||
animatePropertyBy(Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotation(float value) {
|
||||
animateProperty(ROTATION, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationBy(float value) {
|
||||
animatePropertyBy(ROTATION, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationX(float value) {
|
||||
animateProperty(ROTATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationXBy(float value) {
|
||||
animatePropertyBy(ROTATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationY(float value) {
|
||||
animateProperty(ROTATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationYBy(float value) {
|
||||
animatePropertyBy(ROTATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationX(float value) {
|
||||
animateProperty(TRANSLATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationXBy(float value) {
|
||||
animatePropertyBy(TRANSLATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationY(float value) {
|
||||
animateProperty(TRANSLATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationYBy(float value) {
|
||||
animatePropertyBy(TRANSLATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleX(float value) {
|
||||
animateProperty(SCALE_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleXBy(float value) {
|
||||
animatePropertyBy(SCALE_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleY(float value) {
|
||||
animateProperty(SCALE_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleYBy(float value) {
|
||||
animatePropertyBy(SCALE_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alpha(float value) {
|
||||
animateProperty(ALPHA, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alphaBy(float value) {
|
||||
animatePropertyBy(ALPHA, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the underlying Animator for a set of properties. We use a single animator that
|
||||
* simply runs from 0 to 1, and then use that fractional value to set each property
|
||||
* value accordingly.
|
||||
*/
|
||||
private void startAnimation() {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
|
||||
ArrayList<NameValuesHolder> nameValueList =
|
||||
(ArrayList<NameValuesHolder>) mPendingAnimations.clone();
|
||||
mPendingAnimations.clear();
|
||||
int propertyMask = 0;
|
||||
int propertyCount = nameValueList.size();
|
||||
for (int i = 0; i < propertyCount; ++i) {
|
||||
NameValuesHolder nameValuesHolder = nameValueList.get(i);
|
||||
propertyMask |= nameValuesHolder.mNameConstant;
|
||||
}
|
||||
mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
|
||||
animator.addUpdateListener(mAnimatorEventListener);
|
||||
animator.addListener(mAnimatorEventListener);
|
||||
if (mStartDelaySet) {
|
||||
animator.setStartDelay(mStartDelay);
|
||||
}
|
||||
if (mDurationSet) {
|
||||
animator.setDuration(mDuration);
|
||||
}
|
||||
if (mInterpolatorSet) {
|
||||
animator.setInterpolator(mInterpolator);
|
||||
}
|
||||
animator.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by the various x(), y(), etc. methods. This stores the
|
||||
* constant name for the property along with the from/delta values that will be used to
|
||||
* calculate and set the property during the animation. This structure is added to the
|
||||
* pending animations, awaiting the eventual start() of the underlying animator. A
|
||||
* Runnable is posted to start the animation, and any pending such Runnable is canceled
|
||||
* (which enables us to end up starting just one animator for all of the properties
|
||||
* specified at one time).
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param toValue The value to which the property will animate
|
||||
*/
|
||||
private void animateProperty(int constantName, float toValue) {
|
||||
float fromValue = getValue(constantName);
|
||||
float deltaValue = toValue - fromValue;
|
||||
animatePropertyBy(constantName, fromValue, deltaValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by the various xBy(), yBy(), etc. methods. This method is
|
||||
* just like animateProperty(), except the value is an offset from the property's
|
||||
* current value, instead of an absolute "to" value.
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param byValue The amount by which the property will change
|
||||
*/
|
||||
private void animatePropertyBy(int constantName, float byValue) {
|
||||
float fromValue = getValue(constantName);
|
||||
animatePropertyBy(constantName, fromValue, byValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by animateProperty() and animatePropertyBy(), which handles the
|
||||
* details of adding a pending animation and posting the request to start the animation.
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param startValue The starting value of the property
|
||||
* @param byValue The amount by which the property will change
|
||||
*/
|
||||
private void animatePropertyBy(int constantName, float startValue, float byValue) {
|
||||
// First, cancel any existing animations on this property
|
||||
if (mAnimatorMap.size() > 0) {
|
||||
Animator animatorToCancel = null;
|
||||
Set<Animator> animatorSet = mAnimatorMap.keySet();
|
||||
for (Animator runningAnim : animatorSet) {
|
||||
PropertyBundle bundle = mAnimatorMap.get(runningAnim);
|
||||
if (bundle.cancel(constantName)) {
|
||||
// property was canceled - cancel the animation if it's now empty
|
||||
// Note that it's safe to break out here because every new animation
|
||||
// on a property will cancel a previous animation on that property, so
|
||||
// there can only ever be one such animation running.
|
||||
if (bundle.mPropertyMask == NONE) {
|
||||
// the animation is no longer changing anything - cancel it
|
||||
animatorToCancel = runningAnim;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (animatorToCancel != null) {
|
||||
animatorToCancel.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
|
||||
mPendingAnimations.add(nameValuePair);
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.removeCallbacks(mAnimationStarter);
|
||||
v.post(mAnimationStarter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method handles setting the property values directly in the View object's fields.
|
||||
* propertyConstant tells it which property should be set, value is the value to set
|
||||
* the property to.
|
||||
*
|
||||
* @param propertyConstant The property to be set
|
||||
* @param value The value to set the property to
|
||||
*/
|
||||
private void setValue(int propertyConstant, float value) {
|
||||
//final View.TransformationInfo info = mView.mTransformationInfo;
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
switch (propertyConstant) {
|
||||
case TRANSLATION_X:
|
||||
//info.mTranslationX = value;
|
||||
v.setTranslationX(value);
|
||||
break;
|
||||
case TRANSLATION_Y:
|
||||
//info.mTranslationY = value;
|
||||
v.setTranslationY(value);
|
||||
break;
|
||||
case ROTATION:
|
||||
//info.mRotation = value;
|
||||
v.setRotation(value);
|
||||
break;
|
||||
case ROTATION_X:
|
||||
//info.mRotationX = value;
|
||||
v.setRotationX(value);
|
||||
break;
|
||||
case ROTATION_Y:
|
||||
//info.mRotationY = value;
|
||||
v.setRotationY(value);
|
||||
break;
|
||||
case SCALE_X:
|
||||
//info.mScaleX = value;
|
||||
v.setScaleX(value);
|
||||
break;
|
||||
case SCALE_Y:
|
||||
//info.mScaleY = value;
|
||||
v.setScaleY(value);
|
||||
break;
|
||||
case X:
|
||||
//info.mTranslationX = value - v.mLeft;
|
||||
v.setX(value);
|
||||
break;
|
||||
case Y:
|
||||
//info.mTranslationY = value - v.mTop;
|
||||
v.setY(value);
|
||||
break;
|
||||
case ALPHA:
|
||||
//info.mAlpha = value;
|
||||
v.setAlpha(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the value of the named property from the View object.
|
||||
*
|
||||
* @param propertyConstant The property whose value should be returned
|
||||
* @return float The value of the named property
|
||||
*/
|
||||
private float getValue(int propertyConstant) {
|
||||
//final View.TransformationInfo info = mView.mTransformationInfo;
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
switch (propertyConstant) {
|
||||
case TRANSLATION_X:
|
||||
//return info.mTranslationX;
|
||||
return v.getTranslationX();
|
||||
case TRANSLATION_Y:
|
||||
//return info.mTranslationY;
|
||||
return v.getTranslationY();
|
||||
case ROTATION:
|
||||
//return info.mRotation;
|
||||
return v.getRotation();
|
||||
case ROTATION_X:
|
||||
//return info.mRotationX;
|
||||
return v.getRotationX();
|
||||
case ROTATION_Y:
|
||||
//return info.mRotationY;
|
||||
return v.getRotationY();
|
||||
case SCALE_X:
|
||||
//return info.mScaleX;
|
||||
return v.getScaleX();
|
||||
case SCALE_Y:
|
||||
//return info.mScaleY;
|
||||
return v.getScaleY();
|
||||
case X:
|
||||
//return v.mLeft + info.mTranslationX;
|
||||
return v.getX();
|
||||
case Y:
|
||||
//return v.mTop + info.mTranslationY;
|
||||
return v.getY();
|
||||
case ALPHA:
|
||||
//return info.mAlpha;
|
||||
return v.getAlpha();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class holds information about the overall animation being run on the set of
|
||||
* properties. The mask describes which properties are being animated and the
|
||||
* values holder is the list of all property/value objects.
|
||||
*/
|
||||
private static class PropertyBundle {
|
||||
int mPropertyMask;
|
||||
ArrayList<NameValuesHolder> mNameValuesHolder;
|
||||
|
||||
PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
|
||||
mPropertyMask = propertyMask;
|
||||
mNameValuesHolder = nameValuesHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given property from being animated as a part of this
|
||||
* PropertyBundle. If the property was a part of this bundle, it returns
|
||||
* true to indicate that it was, in fact, canceled. This is an indication
|
||||
* to the caller that a cancellation actually occurred.
|
||||
*
|
||||
* @param propertyConstant The property whose cancellation is requested.
|
||||
* @return true if the given property is a part of this bundle and if it
|
||||
* has therefore been canceled.
|
||||
*/
|
||||
boolean cancel(int propertyConstant) {
|
||||
if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
|
||||
int count = mNameValuesHolder.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
|
||||
if (nameValuesHolder.mNameConstant == propertyConstant) {
|
||||
mNameValuesHolder.remove(i);
|
||||
mPropertyMask &= ~propertyConstant;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the information we need to set each property during the animation.
|
||||
* mNameConstant is used to set the appropriate field in View, and the from/delta
|
||||
* values are used to calculate the animated value for a given animation fraction
|
||||
* during the animation.
|
||||
*/
|
||||
private static class NameValuesHolder {
|
||||
int mNameConstant;
|
||||
float mFromValue;
|
||||
float mDeltaValue;
|
||||
|
||||
NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
|
||||
mNameConstant = nameConstant;
|
||||
mFromValue = fromValue;
|
||||
mDeltaValue = deltaValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class that handles the various Animator events. The only ones we care
|
||||
* about are the end event (which we use to clean up the animator map when an animator
|
||||
* finishes) and the update event (which we use to calculate the current value of each
|
||||
* property and then set it on the view object).
|
||||
*/
|
||||
private class AnimatorEventListener
|
||||
implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationStart(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationCancel(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationRepeat(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationEnd(animation);
|
||||
}
|
||||
mAnimatorMap.remove(animation);
|
||||
// If the map is empty, it means all animation are done or canceled, so the listener
|
||||
// isn't needed anymore. Not nulling it would cause it to leak any objects used in
|
||||
// its implementation
|
||||
if (mAnimatorMap.isEmpty()) {
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value for each property and set it on the view. Invalidate
|
||||
* the view object appropriately, depending on which properties are being animated.
|
||||
*
|
||||
* @param animation The animator associated with the properties that need to be
|
||||
* set. This animator holds the animation fraction which we will use to calculate
|
||||
* the current value of each property.
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
// alpha requires slightly different treatment than the other (transform) properties.
|
||||
// The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
|
||||
// logic is dependent on how the view handles an internal call to onSetAlpha().
|
||||
// We track what kinds of properties are set, and how alpha is handled when it is
|
||||
// set, and perform the invalidation steps appropriately.
|
||||
//boolean alphaHandled = false;
|
||||
//mView.invalidateParentCaches();
|
||||
float fraction = animation.getAnimatedFraction();
|
||||
PropertyBundle propertyBundle = mAnimatorMap.get(animation);
|
||||
int propertyMask = propertyBundle.mPropertyMask;
|
||||
if ((propertyMask & TRANSFORM_MASK) != 0) {
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.invalidate(/*false*/);
|
||||
}
|
||||
}
|
||||
ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
|
||||
if (valueList != null) {
|
||||
int count = valueList.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NameValuesHolder values = valueList.get(i);
|
||||
float value = values.mFromValue + fraction * values.mDeltaValue;
|
||||
//if (values.mNameConstant == ALPHA) {
|
||||
// alphaHandled = mView.setAlphaNoInvalidation(value);
|
||||
//} else {
|
||||
setValue(values.mNameConstant, value);
|
||||
//}
|
||||
}
|
||||
}
|
||||
/*if ((propertyMask & TRANSFORM_MASK) != 0) {
|
||||
mView.mTransformationInfo.mMatrixDirty = true;
|
||||
mView.mPrivateFlags |= View.DRAWN; // force another invalidation
|
||||
}*/
|
||||
// invalidate(false) in all cases except if alphaHandled gets set to true
|
||||
// via the call to setAlphaNoInvalidation(), above
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.invalidate(/*alphaHandled*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
package com.adins.libs.nineoldandroids.view;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.adins.libs.nineoldandroids.animation.Animator.AnimatorListener;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
class ViewPropertyAnimatorICS extends ViewPropertyAnimator {
|
||||
/**
|
||||
* A value to be returned when the WeakReference holding the native implementation
|
||||
* returns <code>null</code>
|
||||
*/
|
||||
private final static long RETURN_WHEN_NULL = -1L;
|
||||
|
||||
/**
|
||||
* A WeakReference holding the native implementation of ViewPropertyAnimator
|
||||
*/
|
||||
private final WeakReference<android.view.ViewPropertyAnimator> mNative;
|
||||
|
||||
ViewPropertyAnimatorICS(View view) {
|
||||
mNative = new WeakReference<android.view.ViewPropertyAnimator>(view.animate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setDuration(long duration) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.setDuration(duration);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDuration() {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
return n.getDuration();
|
||||
}
|
||||
return RETURN_WHEN_NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setStartDelay(long startDelay) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.setStartDelay(startDelay);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartDelay() {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
return n.getStartDelay();
|
||||
}
|
||||
return RETURN_WHEN_NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setInterpolator(Interpolator interpolator) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.setInterpolator(interpolator);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setListener(final AnimatorListener listener) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
if (listener == null) {
|
||||
n.setListener(null);
|
||||
} else {
|
||||
n.setListener(new android.animation.Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(android.animation.Animator animation) {
|
||||
listener.onAnimationStart(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(android.animation.Animator animation) {
|
||||
listener.onAnimationRepeat(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(android.animation.Animator animation) {
|
||||
listener.onAnimationEnd(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(android.animation.Animator animation) {
|
||||
listener.onAnimationCancel(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator x(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.x(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator xBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.xBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator y(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.y(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator yBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.yBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotation(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotation(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationX(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationX(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationXBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationXBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationY(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationY(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationYBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationYBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationX(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.translationX(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationXBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.translationXBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationY(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.translationY(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationYBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.translationYBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleX(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.scaleX(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleXBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.scaleXBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleY(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.scaleY(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleYBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.scaleYBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alpha(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.alpha(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alphaBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.alphaBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.adins.libs.nineoldandroids.view;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.adins.libs.nineoldandroids.animation.Animator;
|
||||
import com.adins.libs.nineoldandroids.animation.ValueAnimator;
|
||||
import com.adins.libs.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
class ViewPropertyAnimatorPreHC extends ViewPropertyAnimator {
|
||||
/**
|
||||
* Constants used to associate a property being requested and the mechanism used to set
|
||||
* the property (this class calls directly into View to set the properties in question).
|
||||
*/
|
||||
private static final int NONE = 0x0000;
|
||||
private static final int TRANSLATION_X = 0x0001;
|
||||
private static final int TRANSLATION_Y = 0x0002;
|
||||
private static final int SCALE_X = 0x0004;
|
||||
private static final int SCALE_Y = 0x0008;
|
||||
private static final int ROTATION = 0x0010;
|
||||
private static final int ROTATION_X = 0x0020;
|
||||
private static final int ROTATION_Y = 0x0040;
|
||||
private static final int X = 0x0080;
|
||||
private static final int Y = 0x0100;
|
||||
private static final int ALPHA = 0x0200;
|
||||
private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
|
||||
ROTATION | ROTATION_X | ROTATION_Y | X | Y;
|
||||
/**
|
||||
* Proxy animation class which will allow us access to post-Honeycomb properties that were not
|
||||
* otherwise available.
|
||||
*/
|
||||
private final AnimatorProxy mProxy;
|
||||
/**
|
||||
* A WeakReference holding the View whose properties are being animated by this class. This is
|
||||
* set at construction time.
|
||||
*/
|
||||
private final WeakReference<View> mView;
|
||||
/**
|
||||
* This list holds the properties that have been asked to animate. We allow the caller to
|
||||
* request several animations prior to actually starting the underlying animator. This
|
||||
* enables us to run one single animator to handle several properties in parallel. Each
|
||||
* property is tossed onto the pending list until the animation actually starts (which is
|
||||
* done by posting it onto mView), at which time the pending list is cleared and the properties
|
||||
* on that list are added to the list of properties associated with that animator.
|
||||
*/
|
||||
ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
|
||||
/**
|
||||
* The duration of the underlying Animator object. By default, we don't set the duration
|
||||
* on the Animator and just use its default duration. If the duration is ever set on this
|
||||
* Animator, then we use the duration that it was set to.
|
||||
*/
|
||||
private long mDuration;
|
||||
/**
|
||||
* A flag indicating whether the duration has been set on this object. If not, we don't set
|
||||
* the duration on the underlying Animator, but instead just use its default duration.
|
||||
*/
|
||||
private boolean mDurationSet = false;
|
||||
/**
|
||||
* The startDelay of the underlying Animator object. By default, we don't set the startDelay
|
||||
* on the Animator and just use its default startDelay. If the startDelay is ever set on this
|
||||
* Animator, then we use the startDelay that it was set to.
|
||||
*/
|
||||
private long mStartDelay = 0;
|
||||
/**
|
||||
* A flag indicating whether the startDelay has been set on this object. If not, we don't set
|
||||
* the startDelay on the underlying Animator, but instead just use its default startDelay.
|
||||
*/
|
||||
private boolean mStartDelaySet = false;
|
||||
/**
|
||||
* The interpolator of the underlying Animator object. By default, we don't set the interpolator
|
||||
* on the Animator and just use its default interpolator. If the interpolator is ever set on
|
||||
* this Animator, then we use the interpolator that it was set to.
|
||||
*/
|
||||
private /*Time*/ Interpolator mInterpolator;
|
||||
/**
|
||||
* A flag indicating whether the interpolator has been set on this object. If not, we don't set
|
||||
* the interpolator on the underlying Animator, but instead just use its default interpolator.
|
||||
*/
|
||||
private boolean mInterpolatorSet = false;
|
||||
/**
|
||||
* Listener for the lifecycle events of the underlying
|
||||
*/
|
||||
private Animator.AnimatorListener mListener = null;
|
||||
/**
|
||||
* This listener is the mechanism by which the underlying Animator causes changes to the
|
||||
* properties currently being animated, as well as the cleanup after an animation is
|
||||
* complete.
|
||||
*/
|
||||
private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
|
||||
/**
|
||||
* This list tracks the list of properties being animated by any particular animator.
|
||||
* In most situations, there would only ever be one animator running at a time. But it is
|
||||
* possible to request some properties to animate together, then while those properties
|
||||
* are animating, to request some other properties to animate together. The way that
|
||||
* works is by having this map associate the group of properties being animated with the
|
||||
* animator handling the animation. On every update event for an Animator, we ask the
|
||||
* map for the associated properties and set them accordingly.
|
||||
*/
|
||||
private HashMap<Animator, PropertyBundle> mAnimatorMap =
|
||||
new HashMap<Animator, PropertyBundle>();
|
||||
/**
|
||||
* The mechanism by which the user can request several properties that are then animated
|
||||
* together works by posting this Runnable to start the underlying Animator. Every time
|
||||
* a property animation is requested, we cancel any previous postings of the Runnable
|
||||
* and re-post it. This means that we will only ever run the Runnable (and thus start the
|
||||
* underlying animator) after the caller is done setting the properties that should be
|
||||
* animated together.
|
||||
*/
|
||||
private Runnable mAnimationStarter = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startAnimation();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor, called by View. This is private by design, as the user should only
|
||||
* get a ViewPropertyAnimator by calling View.animate().
|
||||
*
|
||||
* @param view The View associated with this ViewPropertyAnimator
|
||||
*/
|
||||
ViewPropertyAnimatorPreHC(View view) {
|
||||
mView = new WeakReference<View>(view);
|
||||
mProxy = AnimatorProxy.wrap(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default value for ValueAnimator. Calling this method
|
||||
* will cause the declared value to be used instead.
|
||||
*
|
||||
* @param duration The length of ensuing property animations, in milliseconds. The value
|
||||
* cannot be negative.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public ViewPropertyAnimator setDuration(long duration) {
|
||||
if (duration < 0) {
|
||||
throw new IllegalArgumentException("Animators cannot have negative duration: " +
|
||||
duration);
|
||||
}
|
||||
mDurationSet = true;
|
||||
mDuration = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current duration of property animations. If the duration was set on this
|
||||
* object, that value is returned. Otherwise, the default value of the underlying Animator
|
||||
* is returned.
|
||||
*
|
||||
* @return The duration of animations, in milliseconds.
|
||||
* @see #setDuration(long)
|
||||
*/
|
||||
public long getDuration() {
|
||||
if (mDurationSet) {
|
||||
return mDuration;
|
||||
} else {
|
||||
// Just return the default from ValueAnimator, since that's what we'd get if
|
||||
// the value has not been set otherwise
|
||||
return new ValueAnimator().getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartDelay() {
|
||||
if (mStartDelaySet) {
|
||||
return mStartDelay;
|
||||
} else {
|
||||
// Just return the default from ValueAnimator (0), since that's what we'd get if
|
||||
// the value has not been set otherwise
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setStartDelay(long startDelay) {
|
||||
if (startDelay < 0) {
|
||||
throw new IllegalArgumentException("Animators cannot have negative duration: " +
|
||||
startDelay);
|
||||
}
|
||||
mStartDelaySet = true;
|
||||
mStartDelay = startDelay;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setInterpolator(/*Time*/Interpolator interpolator) {
|
||||
mInterpolatorSet = true;
|
||||
mInterpolator = interpolator;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
|
||||
mListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (mAnimatorMap.size() > 0) {
|
||||
HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
|
||||
(HashMap<Animator, PropertyBundle>) mAnimatorMap.clone();
|
||||
Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
|
||||
for (Animator runningAnim : animatorSet) {
|
||||
runningAnim.cancel();
|
||||
}
|
||||
}
|
||||
mPendingAnimations.clear();
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.removeCallbacks(mAnimationStarter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator x(float value) {
|
||||
animateProperty(X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator xBy(float value) {
|
||||
animatePropertyBy(X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator y(float value) {
|
||||
animateProperty(Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator yBy(float value) {
|
||||
animatePropertyBy(Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotation(float value) {
|
||||
animateProperty(ROTATION, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationBy(float value) {
|
||||
animatePropertyBy(ROTATION, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationX(float value) {
|
||||
animateProperty(ROTATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationXBy(float value) {
|
||||
animatePropertyBy(ROTATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationY(float value) {
|
||||
animateProperty(ROTATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationYBy(float value) {
|
||||
animatePropertyBy(ROTATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationX(float value) {
|
||||
animateProperty(TRANSLATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationXBy(float value) {
|
||||
animatePropertyBy(TRANSLATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationY(float value) {
|
||||
animateProperty(TRANSLATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationYBy(float value) {
|
||||
animatePropertyBy(TRANSLATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleX(float value) {
|
||||
animateProperty(SCALE_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleXBy(float value) {
|
||||
animatePropertyBy(SCALE_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleY(float value) {
|
||||
animateProperty(SCALE_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleYBy(float value) {
|
||||
animatePropertyBy(SCALE_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alpha(float value) {
|
||||
animateProperty(ALPHA, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alphaBy(float value) {
|
||||
animatePropertyBy(ALPHA, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the underlying Animator for a set of properties. We use a single animator that
|
||||
* simply runs from 0 to 1, and then use that fractional value to set each property
|
||||
* value accordingly.
|
||||
*/
|
||||
private void startAnimation() {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
|
||||
ArrayList<NameValuesHolder> nameValueList =
|
||||
(ArrayList<NameValuesHolder>) mPendingAnimations.clone();
|
||||
mPendingAnimations.clear();
|
||||
int propertyMask = 0;
|
||||
int propertyCount = nameValueList.size();
|
||||
for (int i = 0; i < propertyCount; ++i) {
|
||||
NameValuesHolder nameValuesHolder = nameValueList.get(i);
|
||||
propertyMask |= nameValuesHolder.mNameConstant;
|
||||
}
|
||||
mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
|
||||
animator.addUpdateListener(mAnimatorEventListener);
|
||||
animator.addListener(mAnimatorEventListener);
|
||||
if (mStartDelaySet) {
|
||||
animator.setStartDelay(mStartDelay);
|
||||
}
|
||||
if (mDurationSet) {
|
||||
animator.setDuration(mDuration);
|
||||
}
|
||||
if (mInterpolatorSet) {
|
||||
animator.setInterpolator(mInterpolator);
|
||||
}
|
||||
animator.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by the various x(), y(), etc. methods. This stores the
|
||||
* constant name for the property along with the from/delta values that will be used to
|
||||
* calculate and set the property during the animation. This structure is added to the
|
||||
* pending animations, awaiting the eventual start() of the underlying animator. A
|
||||
* Runnable is posted to start the animation, and any pending such Runnable is canceled
|
||||
* (which enables us to end up starting just one animator for all of the properties
|
||||
* specified at one time).
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param toValue The value to which the property will animate
|
||||
*/
|
||||
private void animateProperty(int constantName, float toValue) {
|
||||
float fromValue = getValue(constantName);
|
||||
float deltaValue = toValue - fromValue;
|
||||
animatePropertyBy(constantName, fromValue, deltaValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by the various xBy(), yBy(), etc. methods. This method is
|
||||
* just like animateProperty(), except the value is an offset from the property's
|
||||
* current value, instead of an absolute "to" value.
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param byValue The amount by which the property will change
|
||||
*/
|
||||
private void animatePropertyBy(int constantName, float byValue) {
|
||||
float fromValue = getValue(constantName);
|
||||
animatePropertyBy(constantName, fromValue, byValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by animateProperty() and animatePropertyBy(), which handles the
|
||||
* details of adding a pending animation and posting the request to start the animation.
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param startValue The starting value of the property
|
||||
* @param byValue The amount by which the property will change
|
||||
*/
|
||||
private void animatePropertyBy(int constantName, float startValue, float byValue) {
|
||||
// First, cancel any existing animations on this property
|
||||
if (mAnimatorMap.size() > 0) {
|
||||
Animator animatorToCancel = null;
|
||||
Set<Animator> animatorSet = mAnimatorMap.keySet();
|
||||
for (Animator runningAnim : animatorSet) {
|
||||
PropertyBundle bundle = mAnimatorMap.get(runningAnim);
|
||||
if (bundle.cancel(constantName)) {
|
||||
// property was canceled - cancel the animation if it's now empty
|
||||
// Note that it's safe to break out here because every new animation
|
||||
// on a property will cancel a previous animation on that property, so
|
||||
// there can only ever be one such animation running.
|
||||
if (bundle.mPropertyMask == NONE) {
|
||||
// the animation is no longer changing anything - cancel it
|
||||
animatorToCancel = runningAnim;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (animatorToCancel != null) {
|
||||
animatorToCancel.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
|
||||
mPendingAnimations.add(nameValuePair);
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.removeCallbacks(mAnimationStarter);
|
||||
v.post(mAnimationStarter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method handles setting the property values directly in the View object's fields.
|
||||
* propertyConstant tells it which property should be set, value is the value to set
|
||||
* the property to.
|
||||
*
|
||||
* @param propertyConstant The property to be set
|
||||
* @param value The value to set the property to
|
||||
*/
|
||||
private void setValue(int propertyConstant, float value) {
|
||||
//final View.TransformationInfo info = mView.mTransformationInfo;
|
||||
switch (propertyConstant) {
|
||||
case TRANSLATION_X:
|
||||
//info.mTranslationX = value;
|
||||
mProxy.setTranslationX(value);
|
||||
break;
|
||||
case TRANSLATION_Y:
|
||||
//info.mTranslationY = value;
|
||||
mProxy.setTranslationY(value);
|
||||
break;
|
||||
case ROTATION:
|
||||
//info.mRotation = value;
|
||||
mProxy.setRotation(value);
|
||||
break;
|
||||
case ROTATION_X:
|
||||
//info.mRotationX = value;
|
||||
mProxy.setRotationX(value);
|
||||
break;
|
||||
case ROTATION_Y:
|
||||
//info.mRotationY = value;
|
||||
mProxy.setRotationY(value);
|
||||
break;
|
||||
case SCALE_X:
|
||||
//info.mScaleX = value;
|
||||
mProxy.setScaleX(value);
|
||||
break;
|
||||
case SCALE_Y:
|
||||
//info.mScaleY = value;
|
||||
mProxy.setScaleY(value);
|
||||
break;
|
||||
case X:
|
||||
//info.mTranslationX = value - mView.mLeft;
|
||||
mProxy.setX(value);
|
||||
break;
|
||||
case Y:
|
||||
//info.mTranslationY = value - mView.mTop;
|
||||
mProxy.setY(value);
|
||||
break;
|
||||
case ALPHA:
|
||||
//info.mAlpha = value;
|
||||
mProxy.setAlpha(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the value of the named property from the View object.
|
||||
*
|
||||
* @param propertyConstant The property whose value should be returned
|
||||
* @return float The value of the named property
|
||||
*/
|
||||
private float getValue(int propertyConstant) {
|
||||
//final View.TransformationInfo info = mView.mTransformationInfo;
|
||||
switch (propertyConstant) {
|
||||
case TRANSLATION_X:
|
||||
//return info.mTranslationX;
|
||||
return mProxy.getTranslationX();
|
||||
case TRANSLATION_Y:
|
||||
//return info.mTranslationY;
|
||||
return mProxy.getTranslationY();
|
||||
case ROTATION:
|
||||
//return info.mRotation;
|
||||
return mProxy.getRotation();
|
||||
case ROTATION_X:
|
||||
//return info.mRotationX;
|
||||
return mProxy.getRotationX();
|
||||
case ROTATION_Y:
|
||||
//return info.mRotationY;
|
||||
return mProxy.getRotationY();
|
||||
case SCALE_X:
|
||||
//return info.mScaleX;
|
||||
return mProxy.getScaleX();
|
||||
case SCALE_Y:
|
||||
//return info.mScaleY;
|
||||
return mProxy.getScaleY();
|
||||
case X:
|
||||
//return mView.mLeft + info.mTranslationX;
|
||||
return mProxy.getX();
|
||||
case Y:
|
||||
//return mView.mTop + info.mTranslationY;
|
||||
return mProxy.getY();
|
||||
case ALPHA:
|
||||
//return info.mAlpha;
|
||||
return mProxy.getAlpha();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class holds information about the overall animation being run on the set of
|
||||
* properties. The mask describes which properties are being animated and the
|
||||
* values holder is the list of all property/value objects.
|
||||
*/
|
||||
private static class PropertyBundle {
|
||||
int mPropertyMask;
|
||||
ArrayList<NameValuesHolder> mNameValuesHolder;
|
||||
|
||||
PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
|
||||
mPropertyMask = propertyMask;
|
||||
mNameValuesHolder = nameValuesHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given property from being animated as a part of this
|
||||
* PropertyBundle. If the property was a part of this bundle, it returns
|
||||
* true to indicate that it was, in fact, canceled. This is an indication
|
||||
* to the caller that a cancellation actually occurred.
|
||||
*
|
||||
* @param propertyConstant The property whose cancellation is requested.
|
||||
* @return true if the given property is a part of this bundle and if it
|
||||
* has therefore been canceled.
|
||||
*/
|
||||
boolean cancel(int propertyConstant) {
|
||||
if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
|
||||
int count = mNameValuesHolder.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
|
||||
if (nameValuesHolder.mNameConstant == propertyConstant) {
|
||||
mNameValuesHolder.remove(i);
|
||||
mPropertyMask &= ~propertyConstant;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the information we need to set each property during the animation.
|
||||
* mNameConstant is used to set the appropriate field in View, and the from/delta
|
||||
* values are used to calculate the animated value for a given animation fraction
|
||||
* during the animation.
|
||||
*/
|
||||
private static class NameValuesHolder {
|
||||
int mNameConstant;
|
||||
float mFromValue;
|
||||
float mDeltaValue;
|
||||
|
||||
NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
|
||||
mNameConstant = nameConstant;
|
||||
mFromValue = fromValue;
|
||||
mDeltaValue = deltaValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class that handles the various Animator events. The only ones we care
|
||||
* about are the end event (which we use to clean up the animator map when an animator
|
||||
* finishes) and the update event (which we use to calculate the current value of each
|
||||
* property and then set it on the view object).
|
||||
*/
|
||||
private class AnimatorEventListener
|
||||
implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationStart(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationCancel(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationRepeat(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationEnd(animation);
|
||||
}
|
||||
mAnimatorMap.remove(animation);
|
||||
// If the map is empty, it means all animation are done or canceled, so the listener
|
||||
// isn't needed anymore. Not nulling it would cause it to leak any objects used in
|
||||
// its implementation
|
||||
if (mAnimatorMap.isEmpty()) {
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value for each property and set it on the view. Invalidate
|
||||
* the view object appropriately, depending on which properties are being animated.
|
||||
*
|
||||
* @param animation The animator associated with the properties that need to be
|
||||
* set. This animator holds the animation fraction which we will use to calculate
|
||||
* the current value of each property.
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
// alpha requires slightly different treatment than the other (transform) properties.
|
||||
// The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
|
||||
// logic is dependent on how the view handles an internal call to onSetAlpha().
|
||||
// We track what kinds of properties are set, and how alpha is handled when it is
|
||||
// set, and perform the invalidation steps appropriately.
|
||||
//boolean alphaHandled = false;
|
||||
//mView.invalidateParentCaches();
|
||||
float fraction = animation.getAnimatedFraction();
|
||||
PropertyBundle propertyBundle = mAnimatorMap.get(animation);
|
||||
int propertyMask = propertyBundle.mPropertyMask;
|
||||
if ((propertyMask & TRANSFORM_MASK) != 0) {
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.invalidate(/*false*/);
|
||||
}
|
||||
}
|
||||
ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
|
||||
if (valueList != null) {
|
||||
int count = valueList.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NameValuesHolder values = valueList.get(i);
|
||||
float value = values.mFromValue + fraction * values.mDeltaValue;
|
||||
//if (values.mNameConstant == ALPHA) {
|
||||
// alphaHandled = mView.setAlphaNoInvalidation(value);
|
||||
//} else {
|
||||
setValue(values.mNameConstant, value);
|
||||
//}
|
||||
}
|
||||
}
|
||||
/*if ((propertyMask & TRANSFORM_MASK) != 0) {
|
||||
mView.mTransformationInfo.mMatrixDirty = true;
|
||||
mView.mPrivateFlags |= View.DRAWN; // force another invalidation
|
||||
}*/
|
||||
// invalidate(false) in all cases except if alphaHandled gets set to true
|
||||
// via the call to setAlphaNoInvalidation(), above
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.invalidate(/*alphaHandled*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,346 @@
|
|||
package com.adins.libs.nineoldandroids.view.animation;
|
||||
|
||||
import android.graphics.Camera;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* A proxy class to allow for modifying post-3.0 view properties on all pre-3.0
|
||||
* platforms. <strong>DO NOT</strong> wrap your views with this class if you
|
||||
* are using {@code ObjectAnimator} as it will handle that itself.
|
||||
*/
|
||||
public final class AnimatorProxy extends Animation {
|
||||
/**
|
||||
* Whether or not the current running platform needs to be proxied.
|
||||
*/
|
||||
public static final boolean NEEDS_PROXY = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
private static final WeakHashMap<View, AnimatorProxy> PROXIES =
|
||||
new WeakHashMap<View, AnimatorProxy>();
|
||||
private final WeakReference<View> mView;
|
||||
private final Camera mCamera = new Camera();
|
||||
private final RectF mBefore = new RectF();
|
||||
private final RectF mAfter = new RectF();
|
||||
private final Matrix mTempMatrix = new Matrix();
|
||||
private boolean mHasPivot;
|
||||
private float mAlpha = 1;
|
||||
private float mPivotX;
|
||||
private float mPivotY;
|
||||
private float mRotationX;
|
||||
private float mRotationY;
|
||||
private float mRotationZ;
|
||||
private float mScaleX = 1;
|
||||
private float mScaleY = 1;
|
||||
private float mTranslationX;
|
||||
private float mTranslationY;
|
||||
private AnimatorProxy(View view) {
|
||||
setDuration(0); //perform transformation immediately
|
||||
setFillAfter(true); //persist transformation beyond duration
|
||||
view.setAnimation(this);
|
||||
mView = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a proxy to allow for modifying post-3.0 view properties on all
|
||||
* pre-3.0 platforms. <strong>DO NOT</strong> wrap your views if you are
|
||||
* using {@code ObjectAnimator} as it will handle that itself.
|
||||
*
|
||||
* @param view View to wrap.
|
||||
* @return Proxy to post-3.0 properties.
|
||||
*/
|
||||
public static AnimatorProxy wrap(View view) {
|
||||
AnimatorProxy proxy = PROXIES.get(view);
|
||||
// This checks if the proxy already exists and whether it still is the animation of the given view
|
||||
if (proxy == null || proxy != view.getAnimation()) {
|
||||
proxy = new AnimatorProxy(view);
|
||||
PROXIES.put(view, proxy);
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return mAlpha;
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
if (mAlpha != alpha) {
|
||||
mAlpha = alpha;
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float getPivotX() {
|
||||
return mPivotX;
|
||||
}
|
||||
|
||||
public void setPivotX(float pivotX) {
|
||||
if (!mHasPivot || mPivotX != pivotX) {
|
||||
prepareForUpdate();
|
||||
mHasPivot = true;
|
||||
mPivotX = pivotX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getPivotY() {
|
||||
return mPivotY;
|
||||
}
|
||||
|
||||
public void setPivotY(float pivotY) {
|
||||
if (!mHasPivot || mPivotY != pivotY) {
|
||||
prepareForUpdate();
|
||||
mHasPivot = true;
|
||||
mPivotY = pivotY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return mRotationZ;
|
||||
}
|
||||
|
||||
public void setRotation(float rotation) {
|
||||
if (mRotationZ != rotation) {
|
||||
prepareForUpdate();
|
||||
mRotationZ = rotation;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getRotationX() {
|
||||
return mRotationX;
|
||||
}
|
||||
|
||||
public void setRotationX(float rotationX) {
|
||||
if (mRotationX != rotationX) {
|
||||
prepareForUpdate();
|
||||
mRotationX = rotationX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getRotationY() {
|
||||
return mRotationY;
|
||||
}
|
||||
|
||||
public void setRotationY(float rotationY) {
|
||||
if (mRotationY != rotationY) {
|
||||
prepareForUpdate();
|
||||
mRotationY = rotationY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getScaleX() {
|
||||
return mScaleX;
|
||||
}
|
||||
|
||||
public void setScaleX(float scaleX) {
|
||||
if (mScaleX != scaleX) {
|
||||
prepareForUpdate();
|
||||
mScaleX = scaleX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getScaleY() {
|
||||
return mScaleY;
|
||||
}
|
||||
|
||||
public void setScaleY(float scaleY) {
|
||||
if (mScaleY != scaleY) {
|
||||
prepareForUpdate();
|
||||
mScaleY = scaleY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public int getScrollX() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getScrollX();
|
||||
}
|
||||
|
||||
public void setScrollX(int value) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.scrollTo(value, view.getScrollY());
|
||||
}
|
||||
}
|
||||
|
||||
public int getScrollY() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getScrollY();
|
||||
}
|
||||
|
||||
public void setScrollY(int value) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.scrollTo(view.getScrollX(), value);
|
||||
}
|
||||
}
|
||||
|
||||
public float getTranslationX() {
|
||||
return mTranslationX;
|
||||
}
|
||||
|
||||
public void setTranslationX(float translationX) {
|
||||
if (mTranslationX != translationX) {
|
||||
prepareForUpdate();
|
||||
mTranslationX = translationX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getTranslationY() {
|
||||
return mTranslationY;
|
||||
}
|
||||
|
||||
public void setTranslationY(float translationY) {
|
||||
if (mTranslationY != translationY) {
|
||||
prepareForUpdate();
|
||||
mTranslationY = translationY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getLeft() + mTranslationX;
|
||||
}
|
||||
|
||||
public void setX(float x) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
setTranslationX(x - view.getLeft());
|
||||
}
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getTop() + mTranslationY;
|
||||
}
|
||||
|
||||
public void setY(float y) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
setTranslationY(y - view.getTop());
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareForUpdate() {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
computeRect(mBefore, view);
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidateAfterUpdate() {
|
||||
View view = mView.get();
|
||||
if (view == null || view.getParent() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final RectF after = mAfter;
|
||||
computeRect(after, view);
|
||||
after.union(mBefore);
|
||||
|
||||
((View) view.getParent()).invalidate(
|
||||
(int) Math.floor(after.left),
|
||||
(int) Math.floor(after.top),
|
||||
(int) Math.ceil(after.right),
|
||||
(int) Math.ceil(after.bottom));
|
||||
}
|
||||
|
||||
private void computeRect(final RectF r, View view) {
|
||||
// compute current rectangle according to matrix transformation
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
|
||||
// use a rectangle at 0,0 to make sure we don't run into issues with scaling
|
||||
r.set(0, 0, w, h);
|
||||
|
||||
final Matrix m = mTempMatrix;
|
||||
m.reset();
|
||||
transformMatrix(m, view);
|
||||
mTempMatrix.mapRect(r);
|
||||
|
||||
r.offset(view.getLeft(), view.getTop());
|
||||
|
||||
// Straighten coords if rotations flipped them
|
||||
if (r.right < r.left) {
|
||||
final float f = r.right;
|
||||
r.right = r.left;
|
||||
r.left = f;
|
||||
}
|
||||
if (r.bottom < r.top) {
|
||||
final float f = r.top;
|
||||
r.top = r.bottom;
|
||||
r.bottom = f;
|
||||
}
|
||||
}
|
||||
|
||||
private void transformMatrix(Matrix m, View view) {
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
final boolean hasPivot = mHasPivot;
|
||||
final float pX = hasPivot ? mPivotX : w / 2f;
|
||||
final float pY = hasPivot ? mPivotY : h / 2f;
|
||||
|
||||
final float rX = mRotationX;
|
||||
final float rY = mRotationY;
|
||||
final float rZ = mRotationZ;
|
||||
if ((rX != 0) || (rY != 0) || (rZ != 0)) {
|
||||
final Camera camera = mCamera;
|
||||
camera.save();
|
||||
camera.rotateX(rX);
|
||||
camera.rotateY(rY);
|
||||
camera.rotateZ(-rZ);
|
||||
camera.getMatrix(m);
|
||||
camera.restore();
|
||||
m.preTranslate(-pX, -pY);
|
||||
m.postTranslate(pX, pY);
|
||||
}
|
||||
|
||||
final float sX = mScaleX;
|
||||
final float sY = mScaleY;
|
||||
if ((sX != 1.0f) || (sY != 1.0f)) {
|
||||
m.postScale(sX, sY);
|
||||
final float sPX = -(pX / w) * ((sX * w) - w);
|
||||
final float sPY = -(pY / h) * ((sY * h) - h);
|
||||
m.postTranslate(sPX, sPY);
|
||||
}
|
||||
|
||||
m.postTranslate(mTranslationX, mTranslationY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
t.setAlpha(mAlpha);
|
||||
transformMatrix(t.getMatrix(), view);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.content.ComponentCallbacks2;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by gigin.ginanjar on 25/02/2016.
|
||||
*/
|
||||
public abstract class AppContext extends MultiDexApplication {
|
||||
protected static Context context = null;
|
||||
protected static List<IMemoryInfo> memInfoList = new ArrayList<AppContext.IMemoryInfo>();
|
||||
protected static AppContext instance;
|
||||
private String versionName;
|
||||
private int versionCode;
|
||||
|
||||
public static AppContext getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Context getAppContext() {
|
||||
return AppContext.context;
|
||||
}
|
||||
|
||||
public static void registerMemoryListener(IMemoryInfo implementor) {
|
||||
memInfoList.add(implementor);
|
||||
}
|
||||
|
||||
public static void unregisterMemoryListener(IMemoryInfo implementor) {
|
||||
memInfoList.remove(implementor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
super.onTrimMemory(level);
|
||||
if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) {
|
||||
try {
|
||||
// Activity at the front will get earliest than activity at the
|
||||
// back
|
||||
for (int i = memInfoList.size() - 1; i >= 0; i--) {
|
||||
try {
|
||||
memInfoList.get(i).goodTimeToReleaseMemory();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// ACRA.init(this);
|
||||
super.onCreate();
|
||||
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public String getVersionName() {
|
||||
if (versionName == null || versionName.isEmpty()) {
|
||||
try {
|
||||
versionName = retrieveVersionName();
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return versionName;
|
||||
}
|
||||
|
||||
private String retrieveVersionName() throws PackageManager.NameNotFoundException {
|
||||
return getPackageManager().getPackageInfo(
|
||||
getPackageName(), 0).versionName;
|
||||
}
|
||||
|
||||
public int getVersionCode() {
|
||||
if (versionCode == 0) {
|
||||
try {
|
||||
versionCode = retrieveVersionCode();
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return versionCode;
|
||||
}
|
||||
|
||||
private int retrieveVersionCode() throws PackageManager.NameNotFoundException {
|
||||
return getPackageManager().getPackageInfo(
|
||||
getPackageName(), 0).versionCode;
|
||||
}
|
||||
|
||||
public abstract Class getHomeClass();
|
||||
|
||||
public interface IMemoryInfo {
|
||||
void goodTimeToReleaseMemory();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,562 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.dao.TaskD;
|
||||
import com.adins.mss.dao.TaskH;
|
||||
import com.adins.mss.foundation.db.dataaccess.TaskDDataAccess;
|
||||
import com.adins.mss.foundation.db.dataaccess.TaskHDataAccess;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import static com.services.NotificationThread.getNotificationIcon;
|
||||
import static java.lang.Thread.NORM_PRIORITY;
|
||||
|
||||
class BackupFormat {
|
||||
@SerializedName("taskH")
|
||||
private TaskH taskH;
|
||||
|
||||
@SerializedName("taskDList")
|
||||
private List<TaskD> taskDList;
|
||||
|
||||
public TaskH getTaskH() {
|
||||
return taskH;
|
||||
}
|
||||
|
||||
public void setTaskH(TaskH taskH) {
|
||||
this.taskH = taskH;
|
||||
}
|
||||
|
||||
public List<TaskD> getTaskDList() {
|
||||
return taskDList;
|
||||
}
|
||||
|
||||
public void setTaskDList(List<TaskD> taskDList) {
|
||||
this.taskDList = taskDList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Backup {
|
||||
private final Context context;
|
||||
private File dir;
|
||||
private static final String ENCRYPTION_ALGORITHM = "AES/ECB/PKCS5Padding";
|
||||
private static final String ENCRYPTION_KEY = "8]6eUcL'b4}xhqC~";
|
||||
|
||||
public static List<String> updatingTask = new ArrayList<>();
|
||||
|
||||
public Backup(Context context) {
|
||||
this.context = context;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
// Request permission if not granted
|
||||
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PackageInfo pInfo;
|
||||
String appName = "";
|
||||
try {
|
||||
pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
appName = pInfo.packageName+"."+BuildConfig.BUILD_TYPE+"/";
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
if(Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MssLocal/" + appName + GlobalData.getSharedGlobalData().getUser().getLogin_id();
|
||||
// String filePath = context.getExternalFilesDir(null) + "/MssLocal/" + appName + GlobalData.getSharedGlobalData().getUser().getLogin_id();
|
||||
// String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath() + "/MssLocal/" + appName + GlobalData.getSharedGlobalData().getUser().getUuid_user();
|
||||
|
||||
this.dir = new File(filePath);
|
||||
// Ensure the directory exists
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
// Debugging output to check the directory
|
||||
Log.d("Backup", "External storage state: " + Environment.getExternalStorageState());
|
||||
Log.d("Backup", "Directory path: " + dir.getAbsolutePath());
|
||||
Log.d("Backup", "Directory exists: " + dir.exists());
|
||||
Log.d("Backup", "Directory readable: " + dir.canRead());
|
||||
Log.d("Backup", "Directory writable: " + dir.canWrite());
|
||||
Log.d("Backup", "Available space: " + dir.getFreeSpace());
|
||||
}
|
||||
|
||||
private void showNotifBackup(String aggrNo, String content) {
|
||||
String title;
|
||||
if(!aggrNo.isEmpty()) {
|
||||
title = "Task Backup - " + aggrNo;
|
||||
} else {
|
||||
title = "Task Backup";
|
||||
}
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "backup_channel");
|
||||
builder.setSmallIcon(getNotificationIcon());
|
||||
builder.setContentTitle(title);
|
||||
builder.setContentText(content);
|
||||
builder.setPriority(NORM_PRIORITY);
|
||||
NotificationCompat.BigTextStyle inboxStyle =
|
||||
new NotificationCompat.BigTextStyle();
|
||||
// Sets a title for the Inbox in expanded layoutInflater
|
||||
inboxStyle.setBigContentTitle(title);
|
||||
inboxStyle.bigText(content);
|
||||
inboxStyle.setSummaryText(context.getString(com.adins.mss.base.R.string.click_to_open));
|
||||
|
||||
|
||||
builder.setDefaults(android.app.Notification.DEFAULT_ALL);
|
||||
builder.setStyle(inboxStyle);
|
||||
builder.setAutoCancel(true);
|
||||
|
||||
NotificationManager mNotificationManager =
|
||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
{
|
||||
String channelId = "backup_channel";
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
channelId,
|
||||
title,
|
||||
NotificationManager.IMPORTANCE_HIGH);
|
||||
mNotificationManager.createNotificationChannel(channel);
|
||||
builder.setChannelId(channelId);
|
||||
}
|
||||
|
||||
mNotificationManager.notify(1, builder.build());
|
||||
}
|
||||
|
||||
public byte[] encrypt(String backupData) {
|
||||
try {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
|
||||
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||
byte[] ciphertextBytes = backupData.getBytes("UTF-8");
|
||||
return cipher.doFinal(ciphertextBytes);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (Error err) {
|
||||
err.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String decrypt(InputStream encryptedStream) {
|
||||
try {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||
|
||||
CipherInputStream cipherInputStream = new CipherInputStream(encryptedStream, cipher);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = cipherInputStream.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
return new String(output.toByteArray(), "UTF-8");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (Error err) {
|
||||
err.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private SecretKey getSecretKey() throws NoSuchAlgorithmException {
|
||||
byte[] keyBytes = ENCRYPTION_KEY.getBytes();
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ENCRYPTION_ALGORITHM);
|
||||
return secretKeySpec;
|
||||
}
|
||||
|
||||
public BackupFormat getCurrentLocal(String uuidTaskH) {
|
||||
if (dir.exists()) {
|
||||
try {
|
||||
File backupData = new File(dir, uuidTaskH);
|
||||
FileInputStream inputStream = new FileInputStream(backupData);
|
||||
|
||||
String jsonBackup = decrypt(inputStream);
|
||||
|
||||
if (jsonBackup != null) {
|
||||
Type type = new TypeToken<BackupFormat>() {}.getType();
|
||||
return new Gson().fromJson(jsonBackup, type);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (Error err){
|
||||
err.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTask(List<TaskH> taskHList) {
|
||||
if(null != taskHList && taskHList.size() > 0) {
|
||||
new RemoveTask(taskHList).execute();
|
||||
}
|
||||
}
|
||||
|
||||
private int removeBackup(List<TaskH> taskHList, int attempt) {
|
||||
int deletedCount = 0;
|
||||
|
||||
if (taskHList.size() > 0 && attempt <= 10) {
|
||||
List<TaskH> tempTaskH = new ArrayList<>(taskHList);
|
||||
|
||||
for (TaskH taskH : tempTaskH) {
|
||||
File file = new File(dir, taskH.getTask_id());
|
||||
if (!updatingTask.contains(taskH.getUuid_task_h())) {
|
||||
if (file.exists()) {
|
||||
if (file.delete()) {
|
||||
taskHList.remove(taskH);
|
||||
deletedCount++;
|
||||
} else{
|
||||
taskHList.remove(taskH);
|
||||
}
|
||||
} else {
|
||||
taskHList.remove(taskH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (taskHList.size() > 0) {
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
deletedCount += removeBackup(taskHList, attempt + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return deletedCount;
|
||||
}
|
||||
|
||||
private class RemoveTask extends AsyncTask<Void, Void, Integer> {
|
||||
List<TaskH> taskHList;
|
||||
|
||||
private RemoveTask(List<TaskH> taskHList) {
|
||||
this.taskHList = taskHList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
if (taskHList.size() == 1) {
|
||||
showNotifBackup(taskHList.get(0).getTask_id(), context.getString(R.string.delete_backup_progress));
|
||||
} else if (taskHList.size() > 1) {
|
||||
showNotifBackup("", context.getString(R.string.delete_backup_progress));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
try {
|
||||
return removeBackup(new ArrayList<>(taskHList), 1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer integer) {
|
||||
super.onPostExecute(integer);
|
||||
|
||||
if(integer > 0) {
|
||||
if(taskHList.size() == 1) {
|
||||
showNotifBackup(taskHList.get(0).getTask_id(), context.getString(R.string.delete_backup_success));
|
||||
} else if(taskHList.size() > 1) {
|
||||
if(taskHList.size() == integer) {
|
||||
showNotifBackup("", context.getString(R.string.delete_backup_success));
|
||||
} else {
|
||||
showNotifBackup("", context.getString(R.string.delete_backup_half_failed));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(taskHList.size() == 1) {
|
||||
showNotifBackup(taskHList.get(0).getTask_id(), context.getString(R.string.delete_backup_failed));
|
||||
} else if(taskHList.size() > 1) {
|
||||
showNotifBackup("", context.getString(R.string.delete_backup_failed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void performBackup(TaskH taskH) {
|
||||
if(Thread.currentThread() != Looper.getMainLooper().getThread()) {
|
||||
//called from non main thread
|
||||
if (null != taskH) {
|
||||
performBackups(taskH);
|
||||
}
|
||||
} else {
|
||||
//called from main thread
|
||||
if (null != taskH) {
|
||||
new PerformBackupTask(taskH).execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void performBackups(TaskH taskH) {
|
||||
updatingTask.add(taskH.getUuid_task_h());
|
||||
showNotifBackup(taskH.getTask_id(), context.getString(R.string.update_backup_progress));
|
||||
|
||||
BackupFormat backupFormat = new BackupFormat();
|
||||
|
||||
boolean isSuccess = false;
|
||||
|
||||
try {
|
||||
List<TaskD> taskDList = TaskDDataAccess.getListByTaskH(context, taskH.getUuid_task_h());
|
||||
|
||||
backupFormat.setTaskH(taskH);
|
||||
backupFormat.setTaskDList(taskDList);
|
||||
|
||||
Gson gsonBackupFormat = new Gson();
|
||||
byte[] encryptedJson = encrypt(gsonBackupFormat.toJson(backupFormat));
|
||||
|
||||
FileOutputStream outputStream = null;
|
||||
|
||||
try {
|
||||
if(!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
long requiredSpace = encryptedJson.length;
|
||||
long availableSpace = dir.getFreeSpace();
|
||||
|
||||
if (requiredSpace < availableSpace) {
|
||||
File file = new File(dir, taskH.getTask_id());
|
||||
outputStream = new FileOutputStream(file);
|
||||
outputStream.write(encryptedJson);
|
||||
outputStream.close();
|
||||
|
||||
isSuccess = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
isSuccess = false;
|
||||
} finally {
|
||||
assert outputStream != null;
|
||||
outputStream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
isSuccess = false;
|
||||
}
|
||||
|
||||
if(isSuccess) {
|
||||
showNotifBackup(taskH.getTask_id(), context.getString(R.string.update_backup_success));
|
||||
} else {
|
||||
showNotifBackup(taskH.getTask_id(), context.getString(R.string.update_backup_failed));
|
||||
}
|
||||
|
||||
updatingTask.remove(taskH.getUuid_task_h());
|
||||
}
|
||||
|
||||
private class PerformBackupTask extends AsyncTask<Void, Void, Boolean> {
|
||||
BackupFormat backupFormat;
|
||||
ProgressDialog progressDialog;
|
||||
TaskH taskH;
|
||||
|
||||
private PerformBackupTask(TaskH taskH) {
|
||||
this.taskH = taskH;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
|
||||
try {
|
||||
progressDialog = ProgressDialog.show(context,
|
||||
"", context.getString(R.string.progressWait), true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
updatingTask.add(taskH.getUuid_task_h());
|
||||
showNotifBackup(taskH.getTask_id(), context.getString(R.string.update_backup_progress));
|
||||
|
||||
backupFormat = new BackupFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
if(!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
backupFormat = new BackupFormat();
|
||||
try {
|
||||
|
||||
List<TaskD> taskDList = TaskDDataAccess.getListByTaskH(context, taskH.getUuid_task_h());
|
||||
|
||||
backupFormat.setTaskH(taskH);
|
||||
backupFormat.setTaskDList(taskDList);
|
||||
|
||||
Gson gsonBackupFormat = new Gson();
|
||||
byte[] encryptedJson = encrypt(gsonBackupFormat.toJson(backupFormat));
|
||||
|
||||
FileOutputStream outputStream = null;
|
||||
|
||||
try {
|
||||
long requiredSpace = encryptedJson.length;
|
||||
long availableSpace = dir.getFreeSpace();
|
||||
|
||||
if (requiredSpace > availableSpace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File file = new File(dir, taskH.getTask_id());
|
||||
outputStream = new FileOutputStream(file);
|
||||
outputStream.write(encryptedJson);
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
assert outputStream != null;
|
||||
outputStream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean aBoolean) {
|
||||
super.onPostExecute(aBoolean);
|
||||
|
||||
if (null != progressDialog && progressDialog.isShowing()){
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
updatingTask.remove(taskH.getUuid_task_h());
|
||||
if(aBoolean) {
|
||||
showNotifBackup(taskH.getTask_id(), context.getString(R.string.update_backup_success));
|
||||
} else {
|
||||
showNotifBackup(taskH.getTask_id(), context.getString(R.string.update_backup_failed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void performRestore() {
|
||||
RetrieveBackupTask retrieveBackup = new RetrieveBackupTask();
|
||||
retrieveBackup.execute();
|
||||
}
|
||||
|
||||
private class RetrieveBackupTask extends AsyncTask<Void, Void, Integer> {
|
||||
ProgressDialog progressDialog;
|
||||
BackupFormat backupFormat;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
progressDialog = ProgressDialog.show(context,
|
||||
"", context.getString(R.string.progressWait), true);
|
||||
showNotifBackup("", context.getString(R.string.restore_backup_progress));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
String uuidTaskHList[] = dir.list();
|
||||
|
||||
int restoredTask = 0;
|
||||
|
||||
if(null != uuidTaskHList && uuidTaskHList.length > 0) {
|
||||
for (int i = 0; i < uuidTaskHList.length; i++) {
|
||||
backupFormat = getCurrentLocal(uuidTaskHList[i]);
|
||||
|
||||
if (backupFormat == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
TaskHDataAccess.addOrReplace(context, backupFormat.getTaskH());
|
||||
TaskDDataAccess.addOrReplace(context, backupFormat.getTaskDList());
|
||||
|
||||
restoredTask++;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return restoredTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer integer) {
|
||||
super.onPostExecute(integer);
|
||||
|
||||
if (null != progressDialog && progressDialog.isShowing()){
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(integer == 0) {
|
||||
showNotifBackup("", context.getString(R.string.restore_backup_failed));
|
||||
} else {
|
||||
showNotifBackup("", context.getString(R.string.restore_backup_success) + integer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
/**
|
||||
* BaseCommunicationModel provides a class with basic parameters needed in most communication with MSS Server,
|
||||
* like user login Id and IMEI code. Any class which are going to communicate in JSON should use/subclass this model object
|
||||
* to convert to JSON to ensure the same JSON format with MSS Server's JSON
|
||||
*
|
||||
* @author glen.iglesias
|
||||
* @deprecated as of 17 Dec 2014, communication should use MssRequestType and MssResponseType as standard format
|
||||
*/
|
||||
public class BaseCommunicationModel {
|
||||
|
||||
protected String osName;
|
||||
protected String userId;
|
||||
protected String deviceModel;
|
||||
protected String imei;
|
||||
protected String imsi;
|
||||
protected String pin;
|
||||
protected String androidId;
|
||||
|
||||
public BaseCommunicationModel() {
|
||||
}
|
||||
|
||||
public BaseCommunicationModel(boolean useDefault) {
|
||||
if (useDefault) {
|
||||
|
||||
GlobalData gd = GlobalData.getSharedGlobalData();
|
||||
|
||||
osName = gd.getOsName();
|
||||
deviceModel = gd.getDeviceModel();
|
||||
imei = gd.getImei();
|
||||
imsi = gd.getImsi();
|
||||
pin = "ANDROID";
|
||||
androidId = GlobalData.getSharedGlobalData().getAndroidId();
|
||||
userId = gd.getUser().getLogin_id();
|
||||
}
|
||||
}
|
||||
|
||||
public String getOsName() {
|
||||
return osName;
|
||||
}
|
||||
|
||||
public void setOsName(String osName) {
|
||||
this.osName = osName;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getDeviceModel() {
|
||||
return deviceModel;
|
||||
}
|
||||
|
||||
public void setDeviceModel(String deviceModel) {
|
||||
this.deviceModel = deviceModel;
|
||||
}
|
||||
|
||||
public String getImei() {
|
||||
return imei;
|
||||
}
|
||||
|
||||
public void setImei(String imei) {
|
||||
this.imei = imei;
|
||||
}
|
||||
|
||||
public String getImsi() {
|
||||
return imsi;
|
||||
}
|
||||
|
||||
public void setImsi(String imsi) {
|
||||
this.imsi = imsi;
|
||||
}
|
||||
|
||||
public String getPin() {
|
||||
return pin;
|
||||
}
|
||||
|
||||
public void setPin(String pin) {
|
||||
this.pin = pin;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,423 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.util.LocaleHelper;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.foundation.camera.Camera;
|
||||
import com.adins.mss.foundation.camera.ImageCallBack;
|
||||
import com.adins.mss.foundation.image.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Created by winy.firdasari on 14/01/2015.
|
||||
*/
|
||||
public class CameraPreviewActivity extends Activity {
|
||||
|
||||
// ---
|
||||
private static final int BACK_MENU_ID = Menu.FIRST;
|
||||
private static final int OPTIONS_MENU_ID = Menu.FIRST + 1;
|
||||
private static final int CAPTURE_MENU_ID = Menu.FIRST + 2;
|
||||
RelativeLayout container;
|
||||
Context context;
|
||||
boolean hasCamera;
|
||||
private Preview mPreview;
|
||||
private ListAdapter listPicSize;
|
||||
private int rotate = 0;
|
||||
private Button btCapture;
|
||||
private Activity activity;
|
||||
private int actualWidht = Utils.picWidth;
|
||||
private int actualHeight = Utils.picHeight;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Hide the window title.
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
context = this;
|
||||
mPreview = new Preview(this);
|
||||
setContentView(mPreview);
|
||||
hasCamera = Camera.checkCameraHardware(this);
|
||||
|
||||
setContentView(R.layout.camera_preview_layout);
|
||||
container = (RelativeLayout) findViewById(R.id.container);
|
||||
|
||||
LinearLayout previewContainer = (LinearLayout) findViewById(R.id.previewContainer);
|
||||
previewContainer.addView(mPreview);
|
||||
|
||||
btCapture = (Button) findViewById(R.id.btCaptureCam);
|
||||
|
||||
btCapture.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mPreview.mCamera.setAutoFocus();
|
||||
mPreview.mCamera.setFlashAuto();
|
||||
mPreview.mCamera.getPicture(new ImageCallBack() {
|
||||
@Override
|
||||
public void onPictureTaken(byte[] bytes, Object o) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(Camera.BUND_KEY_IMAGE_BYTE, bytes);
|
||||
setResult(Global.REQUEST_CAMERA, intent);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
this.activity = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
Context context = newBase;
|
||||
Locale locale;
|
||||
try{
|
||||
locale = new Locale(GlobalData.getSharedGlobalData().getLocale());
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} catch (Exception e) {
|
||||
locale = new Locale(LocaleHelper.ENGLSIH);
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} finally {
|
||||
super.attachBaseContext(context);
|
||||
}
|
||||
}
|
||||
public boolean getLCDSceenTipeLandscape() {
|
||||
boolean result = false;
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(dm);
|
||||
String str_ScreenSize = "The Android Screen is: W="
|
||||
+ dm.widthPixels
|
||||
+ " x H="
|
||||
+ dm.heightPixels;
|
||||
|
||||
result = dm.widthPixels > dm.heightPixels;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
menu.add(0, BACK_MENU_ID, 0, "Back");
|
||||
menu.add(0, OPTIONS_MENU_ID, 0, "Options");
|
||||
menu.add(0, CAPTURE_MENU_ID, 0, "Capture");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case BACK_MENU_ID:
|
||||
this.finish();
|
||||
return true;
|
||||
case OPTIONS_MENU_ID:
|
||||
this.showOptions();
|
||||
return true;
|
||||
case CAPTURE_MENU_ID:
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void showOptions() {
|
||||
this.loadSupportedPicSize();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle("Picture Size");
|
||||
builder.setSingleChoiceItems(listPicSize, -1, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int item) {
|
||||
String resolution = (String) listPicSize.getItem(item);
|
||||
String[] sz = resolution.split("x");
|
||||
int w = Integer.parseInt(sz[0]);
|
||||
int h = Integer.parseInt(sz[1]);
|
||||
|
||||
mPreview.setPictureSize(w, h);
|
||||
mPreview.mCamera.getCamera().stopPreview();
|
||||
android.hardware.Camera.Size previewSize = mPreview.getOptimalPreviewSize(w, h);
|
||||
mPreview.setPreviewSize(previewSize.width, previewSize.height);
|
||||
mPreview.mCamera.getCamera().startPreview();
|
||||
try {
|
||||
dialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
Toast.makeText(getApplicationContext(), getString(R.string.picture_resolution, resolution), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void loadSupportedPicSize() {
|
||||
if (listPicSize == null) {
|
||||
List<String> listSize = mPreview.getSupportedPictureSize();
|
||||
listPicSize = new ArrayAdapter<String>(this, R.layout.picture_size_list, listSize);
|
||||
}
|
||||
}
|
||||
|
||||
public class Preview extends SurfaceView implements SurfaceHolder.Callback {
|
||||
private SurfaceHolder mHolder;
|
||||
private Camera mCamera;
|
||||
|
||||
public Preview(Context context) {
|
||||
super(context);
|
||||
mHolder = getHolder();
|
||||
mHolder.addCallback(this);
|
||||
}
|
||||
|
||||
public List<String> getSupportedPictureSize() {
|
||||
List<android.hardware.Camera.Size> listSize = mCamera.getCamera().getParameters().getSupportedPictureSizes();
|
||||
List<String> listSizeStr = new ArrayList<>();
|
||||
|
||||
for (android.hardware.Camera.Size size : listSize) {
|
||||
listSizeStr.add(size.width + "x" + size.height);
|
||||
}
|
||||
|
||||
return listSizeStr;
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
try {
|
||||
android.hardware.Camera cam = android.hardware.Camera.open();
|
||||
mCamera = new Camera(context, activity, cam, cam.getParameters());
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
|
||||
|
||||
// default to set picture size to lowest resolution
|
||||
List<android.hardware.Camera.Size> listSupportedSize = mCamera.getCamera().getParameters().getSupportedPictureSizes();
|
||||
if (listSupportedSize != null && !listSupportedSize.isEmpty()) {
|
||||
android.hardware.Camera.Size minimumSize = listSupportedSize.get(searchMostSuportedSizeFromParam(listSupportedSize));
|
||||
android.hardware.Camera.Parameters parameters = mCamera.getCamera().getParameters();
|
||||
parameters.setPictureSize(minimumSize.width, minimumSize.height);
|
||||
mCamera.getCamera().setParameters(parameters);
|
||||
}
|
||||
|
||||
try {
|
||||
mCamera.getCamera().setPreviewDisplay(holder);
|
||||
mCamera.getCamera().setFaceDetectionListener(new com.adins.mss.foundation.camera.FaceDetectionListener());
|
||||
mCamera.startFaceDetection();
|
||||
} catch (IOException exception) {
|
||||
mCamera.getCamera().release();
|
||||
mCamera = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int searchMostSuportedSizeFromParam(List<android.hardware.Camera.Size> listSupportedSize) {
|
||||
android.hardware.Camera.Size suportedSize;
|
||||
int idx = 0;
|
||||
//search for match w x h
|
||||
for (int i = 0; i < listSupportedSize.size(); i++) {
|
||||
if (listSupportedSize.get(i).width == actualWidht && listSupportedSize.get(i).height == actualHeight) {
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
//search for match h
|
||||
for (int i = 0; i < listSupportedSize.size(); i++) {
|
||||
if (listSupportedSize.get(i).height == actualHeight) {
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//search for match w
|
||||
for (int i = 0; i < listSupportedSize.size(); i++) {
|
||||
if (listSupportedSize.get(i).width == actualWidht) {
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return listSupportedSize.size() - 1;
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
mCamera.getCamera().stopPreview();
|
||||
mCamera.getCamera().release();
|
||||
mCamera = null;
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
||||
android.hardware.Camera.Parameters parameters = mCamera.getCamera().getParameters();
|
||||
android.hardware.Camera.Size resultSize = null;
|
||||
|
||||
try {
|
||||
resultSize = getOptimalPreviewSize(w, h);
|
||||
if (resultSize != null) {
|
||||
w = resultSize.width;
|
||||
h = resultSize.height;
|
||||
}
|
||||
if (resultSize != null)
|
||||
parameters.setPreviewSize(w, h);
|
||||
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
resultSize = null;
|
||||
}
|
||||
|
||||
parameters.setPictureFormat(ImageFormat.JPEG);
|
||||
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_AUTO);
|
||||
parameters.setFlashMode(android.hardware.Camera.Parameters.FLASH_MODE_OFF);
|
||||
|
||||
if (resultSize != null) {
|
||||
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
|
||||
android.hardware.Camera.CameraInfo info =
|
||||
new android.hardware.Camera.CameraInfo();
|
||||
android.hardware.Camera.getCameraInfo(android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK, info);
|
||||
int degrees = 0;
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_0:
|
||||
degrees = 0;
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
degrees = 90;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
degrees = 180;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
degrees = 270;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int result;
|
||||
if (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
result = (info.orientation + degrees) % 360;
|
||||
result = (360 - result) % 360; // compensate the mirror
|
||||
} else { // back-facing
|
||||
result = (info.orientation - degrees + 360) % 360;
|
||||
}
|
||||
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
rotate = 90;
|
||||
}
|
||||
|
||||
//khusus untuk device dengan lcd landscape, ex: htc chacha
|
||||
if (result == 90 && getLCDSceenTipeLandscape()) {
|
||||
result = 0;
|
||||
} else if (result == 0 && !getLCDSceenTipeLandscape()) {
|
||||
result = 270;
|
||||
} else if (result == 180 && !getLCDSceenTipeLandscape()) {
|
||||
result = 90;
|
||||
} else if (result == 270 && getLCDSceenTipeLandscape()) {
|
||||
result = 180;
|
||||
}
|
||||
|
||||
mCamera.getCamera().setDisplayOrientation(result);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
mCamera.getCamera().setParameters(parameters);
|
||||
mCamera.getCamera().setFaceDetectionListener(new com.adins.mss.foundation.camera.FaceDetectionListener());
|
||||
mCamera.startFaceDetection();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
parameters = mCamera.getCamera().getParameters();
|
||||
parameters.setPictureFormat(ImageFormat.JPEG);
|
||||
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_AUTO);
|
||||
parameters.setFlashMode(android.hardware.Camera.Parameters.FLASH_MODE_AUTO);
|
||||
|
||||
try {
|
||||
mCamera.getCamera().setParameters(parameters);
|
||||
mCamera.getCamera().setFaceDetectionListener(new com.adins.mss.foundation.camera.FaceDetectionListener());
|
||||
mCamera.startFaceDetection();
|
||||
} catch (Exception e2) {
|
||||
parameters = mCamera.getCamera().getParameters();
|
||||
mCamera.getCamera().setParameters(parameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mCamera.getCamera().startPreview();
|
||||
}
|
||||
|
||||
public void setPictureSize(int width, int height) {
|
||||
android.hardware.Camera.Parameters cp = mCamera.getCamera().getParameters();
|
||||
cp.setPictureSize(width, height);
|
||||
mCamera.getCamera().setParameters(cp);
|
||||
}
|
||||
|
||||
public android.hardware.Camera.Size getOptimalPreviewSize(int picWidth, int picHeight) {
|
||||
List<android.hardware.Camera.Size> sizes = mCamera.getCamera().getParameters().getSupportedPreviewSizes();
|
||||
final double ASPECT_TOLERANCE = 0.1;
|
||||
double targetRatio = (double) picWidth / picHeight;
|
||||
if (sizes == null)
|
||||
return null;
|
||||
|
||||
android.hardware.Camera.Size optimalSize = null;
|
||||
double minDiff = Double.MAX_VALUE;
|
||||
|
||||
int targetHeight = picHeight;
|
||||
|
||||
// Try to find an size match aspect ratio and size
|
||||
for (android.hardware.Camera.Size size : sizes) {
|
||||
double ratio = (double) size.width / size.height;
|
||||
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
|
||||
continue;
|
||||
if (Math.abs(size.height - targetHeight) < minDiff) {
|
||||
optimalSize = size;
|
||||
minDiff = Math.abs(size.height - targetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot find the one match the aspect ratio, ignore the
|
||||
// requirement
|
||||
if (optimalSize == null) {
|
||||
minDiff = Double.MAX_VALUE;
|
||||
for (android.hardware.Camera.Size size : sizes) {
|
||||
if (Math.abs(size.height - targetHeight) < minDiff) {
|
||||
optimalSize = size;
|
||||
minDiff = Math.abs(size.height - targetHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
return optimalSize;
|
||||
}
|
||||
|
||||
public void setPreviewSize(int width, int height) {
|
||||
android.hardware.Camera.Parameters cp = mCamera.getCamera().getParameters();
|
||||
cp.setPreviewSize(width, height);
|
||||
mCamera.getCamera().setParameters(cp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.adins.mss.base.util.LocaleHelper;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Created by adityapurwa on 15/04/15.
|
||||
*/
|
||||
public class ChangePasswordActivity extends FragmentActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
ACRA.getErrorReporter().putCustomData("LAST_CLASS_ACCESSED", getClass().getSimpleName());
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_change_password);
|
||||
Fragment fragment = new ChangePasswordFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean(ChangePasswordFragment.AS_ACTIVITY, true);
|
||||
fragment.setArguments(args);
|
||||
FragmentTransaction
|
||||
transaction = getSupportFragmentManager().beginTransaction();
|
||||
transaction.replace(R.id.fragmentRoot, fragment);
|
||||
transaction.addToBackStack(null);
|
||||
transaction.commit();
|
||||
}
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
Context context = newBase;
|
||||
Locale locale;
|
||||
try{
|
||||
locale = new Locale(GlobalData.getSharedGlobalData().getLocale());
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} catch (Exception e) {
|
||||
locale = new Locale(LocaleHelper.ENGLSIH);
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} finally {
|
||||
super.attachBaseContext(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActionBar;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import androidx.fragment.app.Fragment;
|
||||
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 com.adins.mss.base.api.ChangePasswordApi;
|
||||
import com.adins.mss.base.api.ChangePasswordApiCallback;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.dynamicform.form.questions.QuestionsValidator;
|
||||
import com.adins.mss.base.errorhandler.ErrorMessageHandler;
|
||||
import com.adins.mss.base.errorhandler.IShowError;
|
||||
import com.adins.mss.base.login.DefaultLoginModel;
|
||||
import com.adins.mss.base.mainmenu.MainMenuHelper;
|
||||
import com.adins.mss.base.models.ChangePasswordRequestModel;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.dao.User;
|
||||
import com.adins.mss.foundation.db.dataaccess.UserDataAccess;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
/**
|
||||
* Created by adityapurwa on 30/03/15.
|
||||
*/
|
||||
public class ChangePasswordFragment extends Fragment implements IShowError {
|
||||
public static final String AS_ACTIVITY = "ChangePasswordActivity.AS_ACTIVITY";
|
||||
private EditText currentPassword;
|
||||
private EditText newPassword;
|
||||
private EditText retypePassword;
|
||||
private Button changePassword;
|
||||
ErrorMessageHandler errorMessageHandler;
|
||||
|
||||
//bong 7 apr 15 not override
|
||||
public static void onBackPressed() {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onAttach(Context activity) {
|
||||
super.onAttach(activity);
|
||||
ACRA.getErrorReporter().putCustomData("LAST_CLASS_ACCESSED", getClass().getSimpleName());
|
||||
getActivity().getActionBar().setTitle(getString(R.string.title_mn_changepassword));
|
||||
getActivity().getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
||||
errorMessageHandler = new ErrorMessageHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
Utility.freeMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
getActivity().getActionBar().setTitle(getString(R.string.title_mn_changepassword));
|
||||
getActivity().getActionBar().removeAllTabs();
|
||||
getActivity().getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
|
||||
View actionBar = view.findViewById(R.id.actionbar);
|
||||
final boolean asActivity = getArguments().getBoolean(AS_ACTIVITY);
|
||||
if (actionBar != null && asActivity) {
|
||||
actionBar.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
String pwdExp = getActivity().getIntent().getStringExtra(DefaultLoginModel.PWD_EXP);
|
||||
try {
|
||||
if (pwdExp.equals("1")) {
|
||||
errorMessageHandler.processError("",getActivity().getString(R.string.password_expired), ErrorMessageHandler.TOAST_TYPE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
|
||||
|
||||
currentPassword = (EditText) view.findViewById(R.id.currentPassword);
|
||||
newPassword = (EditText) view.findViewById(R.id.newPassword);
|
||||
retypePassword = (EditText) view.findViewById(R.id.retypePassword);
|
||||
changePassword = (Button) view.findViewById(R.id.changePassword);
|
||||
|
||||
changePassword.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (currentPassword.getText() == null || currentPassword.getText().toString().equals("")) {
|
||||
currentPassword.setError(getActivity().getString(R.string.current_password_mandatory));
|
||||
}
|
||||
if (newPassword.getText() == null ||
|
||||
newPassword.getText().toString().equals("")) {
|
||||
newPassword.setError(getActivity().getString(R.string.new_password_mandatory));
|
||||
return;
|
||||
}
|
||||
if (!newPassword.getText().toString().equals(retypePassword.getText().toString())) {
|
||||
errorMessageHandler.processError(""
|
||||
,getActivity().getString(R.string.new_password_equal),
|
||||
ErrorMessageHandler.TOAST_TYPE);
|
||||
return;
|
||||
}
|
||||
if (newPassword.getText().toString().equals(currentPassword.getText().toString())) {
|
||||
errorMessageHandler.processError(""
|
||||
,getActivity().getString(R.string.new_password_different)
|
||||
, ErrorMessageHandler.TOAST_TYPE);
|
||||
}
|
||||
|
||||
ChangePasswordRequestModel request = new ChangePasswordRequestModel();
|
||||
request.setUuid_user(GlobalData.getSharedGlobalData().getUser().getUuid_user());
|
||||
request.setOld_password(currentPassword.getText().toString());
|
||||
request.setNew_password(newPassword.getText().toString());
|
||||
request.setAudit(GlobalData.getSharedGlobalData().getAuditData());
|
||||
|
||||
ChangePasswordApi api = new ChangePasswordApi(getActivity());
|
||||
api.setCallback(new ChangePasswordApiCallback() {
|
||||
@Override
|
||||
public void onFailed(String message) {
|
||||
try {
|
||||
errorMessageHandler.processError(getActivity().getString(R.string.warning_capital)
|
||||
,message
|
||||
, ErrorMessageHandler.TOAST_TYPE);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
errorMessageHandler.processError("","Change Password Error", ErrorMessageHandler.TOAST_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.password_changed), Toast.LENGTH_LONG).show();
|
||||
if (!asActivity) {
|
||||
User user = GlobalData.getSharedGlobalData().getUser();
|
||||
user.setPassword(newPassword.getText().toString());
|
||||
UserDataAccess.addOrReplace(getActivity(), user);
|
||||
MainMenuHelper.doBackFragment(getActivity());
|
||||
} else {
|
||||
User user = GlobalData.getSharedGlobalData().getUser();
|
||||
user.setPassword(newPassword.getText().toString());
|
||||
UserDataAccess.addOrReplace(getActivity(), user);
|
||||
goToSynchronize();
|
||||
Global.syncIntent = null;
|
||||
getActivity().finish();
|
||||
|
||||
}
|
||||
clear();
|
||||
}
|
||||
});
|
||||
|
||||
api.execute(request);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
currentPassword.setText("");
|
||||
newPassword.setText("");
|
||||
retypePassword.setText("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_change_password, container, false);
|
||||
}
|
||||
|
||||
public boolean checkRegex(EditText editText) {
|
||||
String regex = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$";
|
||||
String answer = editText.getText().toString().trim();
|
||||
if ( !answer.isEmpty()) {
|
||||
if (QuestionsValidator.regexIsMatch(answer, regex)) {
|
||||
return true;
|
||||
} else {
|
||||
editText.setError(getActivity().getString(R.string.alpha_numeric_warning));
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.input_not_valid), Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void goToSynchronize() {
|
||||
if (Global.syncIntent != null) {
|
||||
Intent syncIntent = Global.syncIntent;
|
||||
startActivity(syncIntent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String errorSubject, String errorMsg, int notifType) {
|
||||
if(notifType == ErrorMessageHandler.TOAST_TYPE){
|
||||
if(errorSubject == null || errorSubject.equals(""))
|
||||
Toast.makeText(getActivity(), errorMsg, Toast.LENGTH_SHORT).show();
|
||||
else {
|
||||
Toast.makeText(getActivity(), errorSubject+": "+errorMsg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Switch;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.adins.mss.base.util.LocaleHelper;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.foundation.config.ConfigFileReader;
|
||||
import com.adins.mss.foundation.security.storepreferences.ObscuredSharedPreferences;
|
||||
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
||||
public class DeveloperOptionActivity extends AppCompatActivity {
|
||||
|
||||
private Button btnSave;
|
||||
private Switch switchEncrypt;
|
||||
private Switch switchDecrypt;
|
||||
private Switch switchAccessToken;
|
||||
private Switch switchDevMode;
|
||||
private LinearLayout clientIdLayout;
|
||||
private EditText edtClientId;
|
||||
|
||||
private boolean isEncrypt;
|
||||
private boolean isDecrypt;
|
||||
private boolean isAccessTokenEnable;
|
||||
private boolean isByPassEnable;
|
||||
|
||||
private FirebaseAnalytics screenName;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
screenName = FirebaseAnalytics.getInstance(this);
|
||||
|
||||
setContentView(R.layout.new_developer_option_activity);
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setTitleTextColor(getResources().getColor(R.color.fontColorWhite));
|
||||
setSupportActionBar(toolbar);
|
||||
initViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
//Set Firebase screen name
|
||||
screenName.setCurrentScreen(this, getString(R.string.screen_name_developer_option), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
Context context = newBase;
|
||||
Locale locale;
|
||||
try{
|
||||
locale = new Locale(GlobalData.getSharedGlobalData().getLocale());
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} catch (Exception e) {
|
||||
locale = new Locale(LocaleHelper.ENGLSIH);
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} finally {
|
||||
super.attachBaseContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
btnSave = (Button) findViewById(R.id.btnSave);
|
||||
switchDecrypt = (Switch) findViewById(R.id.switchDecrypt);
|
||||
switchEncrypt = (Switch) findViewById(R.id.switchEncrypt);
|
||||
switchAccessToken = (Switch) findViewById(R.id.switchAccessToken);
|
||||
switchDevMode = (Switch) findViewById(R.id.switchDevMode);
|
||||
clientIdLayout = (LinearLayout) findViewById(R.id.layoutClientId);
|
||||
edtClientId = (EditText) findViewById(R.id.edtClientId);
|
||||
final ObscuredSharedPreferences sharedPref = ObscuredSharedPreferences.getPrefs(getApplicationContext(),
|
||||
"GlobalData", Context.MODE_PRIVATE);
|
||||
Properties prop = ConfigFileReader.propertiesFromFile(this, GlobalData.PROPERTY_FILENAME);
|
||||
boolean encrypt = Boolean.parseBoolean(prop.getProperty(GlobalData.PROP_ENCRYPT, "false"));
|
||||
boolean decrypt = Boolean.parseBoolean(prop.getProperty(GlobalData.PROP_DECRYPT, "false"));
|
||||
String propClientId = prop.getProperty(GlobalData.PROP_CLIENT_ID, "android");
|
||||
boolean byPassEnable = Boolean.parseBoolean(prop.getProperty(GlobalData.PROP_IS_BYPASS_DEVELOPER, "false"));
|
||||
boolean hasEncrypt = sharedPref.getBoolean("IS_ENCRYPT", encrypt);
|
||||
boolean hasDecrypt = sharedPref.getBoolean("IS_DECRYPT", decrypt);
|
||||
|
||||
boolean tokenFromPropValue = Boolean.parseBoolean(prop.getProperty(GlobalData.PROP_IS_REQUIRED_ACCESS_TOKEN, "false"));
|
||||
boolean isTokenEnable = sharedPref.getBoolean("IS_ACCESS_TOKEN_ENABLE",false);
|
||||
String firstSetting = sharedPref.getString("IS_DEV_FIRST_SETTING", Global.TRUE_STRING);
|
||||
if(!isTokenEnable && tokenFromPropValue && Global.TRUE_STRING.equalsIgnoreCase(firstSetting)){
|
||||
isTokenEnable = tokenFromPropValue;
|
||||
}
|
||||
final String clientId = sharedPref.getString("CLIENT_ID", propClientId);
|
||||
|
||||
isByPassEnable = sharedPref.getBoolean("IS_BYPASS_ENABLE", byPassEnable);
|
||||
|
||||
switchAccessToken.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
clientIdLayout.setVisibility(View.VISIBLE);
|
||||
edtClientId.setText(clientId);
|
||||
} else {
|
||||
clientIdLayout.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (hasEncrypt) {
|
||||
switchEncrypt.setChecked(true);
|
||||
}
|
||||
if (hasDecrypt) {
|
||||
switchDecrypt.setChecked(true);
|
||||
}
|
||||
if (isTokenEnable) {
|
||||
switchAccessToken.setChecked(true);
|
||||
clientIdLayout.setVisibility(View.VISIBLE);
|
||||
edtClientId.setText(clientId);
|
||||
} else {
|
||||
clientIdLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (isByPassEnable) {
|
||||
switchDevMode.setChecked(true);
|
||||
}
|
||||
|
||||
btnSave.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ObscuredSharedPreferences.Editor sharedPrefEditor = sharedPref.edit();
|
||||
isEncrypt = switchEncrypt.isChecked();
|
||||
isDecrypt = switchDecrypt.isChecked();
|
||||
isAccessTokenEnable = switchAccessToken.isChecked();
|
||||
isByPassEnable = switchDevMode.isChecked();
|
||||
if (isAccessTokenEnable && edtClientId.getText() != null && edtClientId.getText().length() > 0) {
|
||||
String clientId = edtClientId.getText().toString();
|
||||
sharedPrefEditor.putString("CLIENT_ID", clientId);
|
||||
GlobalData.getSharedGlobalData().setClientId(clientId);
|
||||
}
|
||||
|
||||
GlobalData.getSharedGlobalData().setEncrypt(isEncrypt);
|
||||
GlobalData.getSharedGlobalData().setDecrypt(isDecrypt);
|
||||
GlobalData.getSharedGlobalData().setRequiresAccessToken(isAccessTokenEnable);
|
||||
GlobalData.getSharedGlobalData().setByPassDeveloper(isByPassEnable);
|
||||
|
||||
String isFirstSetting = sharedPref.getString("IS_DEV_FIRST_SETTING", Global.TRUE_STRING);
|
||||
if(Global.TRUE_STRING.equalsIgnoreCase(isFirstSetting)){
|
||||
sharedPrefEditor.putString("IS_DEV_FIRST_SETTING",Global.FALSE_STRING);
|
||||
}
|
||||
sharedPrefEditor.putBoolean("IS_ENCRYPT", isEncrypt);
|
||||
sharedPrefEditor.putBoolean("IS_DECRYPT", isDecrypt);
|
||||
sharedPrefEditor.putBoolean("IS_ACCESS_TOKEN_ENABLE", isAccessTokenEnable);
|
||||
sharedPrefEditor.putBoolean("IS_BYPASS_ENABLE", isByPassEnable);
|
||||
|
||||
sharedPrefEditor.commit();
|
||||
|
||||
Toast.makeText(DeveloperOptionActivity.this, getString(R.string.options_saved), Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,70 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
|
||||
public class GlobalUI {
|
||||
|
||||
public static int color01 = 0;
|
||||
public static int color02 = 0;
|
||||
public static int color03 = 0;
|
||||
public static int color04 = 0;
|
||||
public static int color05 = 0;
|
||||
public static int color06 = 0;
|
||||
public static int color07 = 0;
|
||||
public static int color08 = 0;
|
||||
|
||||
public GlobalUI() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public static void setColor01(String hexaColor) {
|
||||
color01 = Color.parseColor(hexaColor);
|
||||
}
|
||||
|
||||
public static void setColor02(String hexaColor) {
|
||||
color02 = Color.parseColor(hexaColor);
|
||||
}
|
||||
|
||||
public static void setColor03(String hexaColor) {
|
||||
color03 = Color.parseColor(hexaColor);
|
||||
}
|
||||
|
||||
public static void setColor04(String hexaColor) {
|
||||
color04 = Color.parseColor(hexaColor);
|
||||
}
|
||||
|
||||
public static void setColor05(String hexaColor) {
|
||||
color05 = Color.parseColor(hexaColor);
|
||||
}
|
||||
|
||||
public static void setColor06(String hexaColor) {
|
||||
color06 = Color.parseColor(hexaColor);
|
||||
}
|
||||
|
||||
public static void setColor07(String hexaColor) {
|
||||
color07 = Color.parseColor(hexaColor);
|
||||
}
|
||||
|
||||
public static void setColor08(String hexaColor) {
|
||||
color08 = Color.parseColor(hexaColor);
|
||||
}
|
||||
|
||||
public static void setAllColor(String hexaColorArr[]) {
|
||||
color01 = Color.parseColor(hexaColorArr[0]);
|
||||
color02 = Color.parseColor(hexaColorArr[1]);
|
||||
color03 = Color.parseColor(hexaColorArr[2]);
|
||||
color04 = Color.parseColor(hexaColorArr[3]);
|
||||
color05 = Color.parseColor(hexaColorArr[4]);
|
||||
color06 = Color.parseColor(hexaColorArr[5]);
|
||||
color07 = Color.parseColor(hexaColorArr[6]);
|
||||
color08 = Color.parseColor(hexaColorArr[7]);
|
||||
}
|
||||
|
||||
public static int getImage(Context context, String fileNamePath) {
|
||||
// int id = context.getResources().getIdentifier("yourpackagename:drawable/" + StringGenerated, null, null);
|
||||
int id = context.getResources().getIdentifier(fileNamePath, null, null);
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.PermissionChecker;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
|
||||
public class LocationPermissionInformationFragment extends Fragment {
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.fragment_location_permission_information, container, false);
|
||||
TextView turnOnLocPermission = view.findViewById(R.id.turn_on_text);
|
||||
TextView gotoTermAndCondition = view.findViewById(R.id.termAndConditionText);
|
||||
TextView gotoPrivacyAndPolicy = view.findViewById(R.id.PrivacyAndPolicyText);
|
||||
|
||||
turnOnLocPermission.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Utility.checkPermissionGranted(getActivity());
|
||||
}
|
||||
});
|
||||
gotoTermAndCondition.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Uri uri = Uri.parse("http://app.ad-ins.com/mobileone/TermsConditions.html"); // missing 'http://' will cause crashed
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
gotoPrivacyAndPolicy.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Uri uri = Uri.parse("http://app.ad-ins.com/mobileone/KebijakanPrivasi.html"); // missing 'http://' will cause crashed
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (getActivity().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
|
||||
getActivity().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
getActivity().getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
} else {
|
||||
if (PermissionChecker.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) == PermissionChecker.PERMISSION_GRANTED &&
|
||||
PermissionChecker.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) == PermissionChecker.PERMISSION_GRANTED) {
|
||||
getActivity().getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,587 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.content.PermissionChecker;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import com.adins.mss.base.commons.Helper;
|
||||
import com.adins.mss.base.commons.ModeledActivity;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.dynamictheme.DynamicTheme;
|
||||
import com.adins.mss.base.dynamictheme.ThemeLoader;
|
||||
import com.adins.mss.base.dynamictheme.ThemeUtility;
|
||||
import com.adins.mss.base.login.DefaultLoginModel;
|
||||
import com.adins.mss.base.login.LoginImpl;
|
||||
import com.adins.mss.base.login.LoginModel;
|
||||
import com.adins.mss.base.syncfile.DownloadParams;
|
||||
import com.adins.mss.base.syncfile.FileDownloader;
|
||||
import com.adins.mss.base.syncfile.FileSyncHelper;
|
||||
import com.adins.mss.base.syncfile.ImportDbFromCsv;
|
||||
import com.adins.mss.base.syncfile.ImportDbParams;
|
||||
import com.adins.mss.base.util.LocaleHelper;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.dao.MobileDataFile;
|
||||
import com.adins.mss.foundation.dialog.DialogManager;
|
||||
import com.adins.mss.foundation.location.LocationTrackingManager;
|
||||
import com.adins.mss.foundation.security.storepreferences.ObscuredSharedPreferences;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics;
|
||||
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
|
||||
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
|
||||
import com.services.RefreshToken;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.adins.mss.base.login.DefaultLoginModel.LOGIN_PREFERENCES;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Aditya Purwa on 1/6/2015.
|
||||
* Activity for login.
|
||||
*/
|
||||
public abstract class LoginActivity extends AppCompatActivity implements ModeledActivity<DefaultLoginModel> {
|
||||
|
||||
public static Context instance;
|
||||
private List<MobileDataFile> data;
|
||||
public static List<MobileDataFile> activeData;
|
||||
public static int currentidx = 0;
|
||||
public static MobileDataFile metadata;
|
||||
//variable penampung
|
||||
static String link, savePath, message;
|
||||
static ProgressDialog pDialog;
|
||||
private final String DevModeEnable = "$ADIMOBILEDEVMODEON$";
|
||||
private final String DevModeDisable = "$ADIMOBILEDEVMODEOFF$";
|
||||
private final String txtDevModeOn = "ENABLE DEVELOPER MODE";
|
||||
private final String txtDevModeOff = "DISABLE DEVELOPER MODE";
|
||||
private final String txtDevModeOnId = "AKTIFKAN MODE PENGEMBANGAN";
|
||||
private final String txtDevModeOffId = "MATIKAN MODE PENGEMBANGAN";
|
||||
public LocationTrackingManager manager;
|
||||
protected ImageView logo;
|
||||
private LoginModel dataContext;
|
||||
private ObscuredSharedPreferences loginPreferences;
|
||||
//bong 1 apr 15 add menu to serverLinkActivity
|
||||
private Menu mainMenu;
|
||||
private LoginImpl loginImpl;
|
||||
protected ThemeLoader themeLoader;
|
||||
private Toolbar toolbar;
|
||||
private View loginHeader;
|
||||
private Button loginButton;
|
||||
private Fragment locPermissionFragment;
|
||||
protected boolean hasLogged;
|
||||
|
||||
public void downloadFiles() {
|
||||
currentidx++;
|
||||
int i = currentidx;
|
||||
metadata = data.get(i);
|
||||
message = "Downloading file " + (i + 1) + " out of " + data.size() + " files.";
|
||||
link = data.get(i).getFile_url();
|
||||
savePath = GlobalData.getSharedGlobalData().getSavePath();
|
||||
if (link != null && !link.isEmpty()) {
|
||||
DownloadParams parameters = new DownloadParams(savePath, instance, message, metadata);
|
||||
FileDownloader downloader = new FileDownloader(instance);
|
||||
downloader.execute(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public static void importFiles() {
|
||||
currentidx++;
|
||||
int i = currentidx;
|
||||
metadata = activeData.get(i);
|
||||
message = "Importing file " + (i + 1) + " out of " + activeData.size() + " files.";
|
||||
ImportDbParams importParams = new ImportDbParams(instance, message, metadata);
|
||||
ImportDbFromCsv importer = new ImportDbFromCsv();
|
||||
importer.execute(importParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_item, menu);
|
||||
|
||||
mainMenu = menu;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
Global.IS_DEV = false;
|
||||
enableMenuItem(false);
|
||||
if (Global.IS_DEV) {
|
||||
enableMenuItem(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void enableMenuItem(boolean enable) {
|
||||
if (enable) {
|
||||
mainMenu.findItem(R.id.menuItem).setVisible(true);
|
||||
mainMenu.findItem(R.id.serverLink).setVisible(true);
|
||||
mainMenu.findItem(R.id.devOption).setVisible(true);
|
||||
} else {
|
||||
mainMenu.findItem(R.id.menuItem).setVisible(false);
|
||||
mainMenu.findItem(R.id.serverLink).setVisible(false);
|
||||
mainMenu.findItem(R.id.devOption).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_UP && KeyEvent.KEYCODE_MENU == keyCode) {
|
||||
if(Global.IS_DEV)
|
||||
mainMenu.performIdentifierAction(R.id.menuItem, 0);
|
||||
return true;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
String title = item.getTitle().toString();
|
||||
if (getString(R.string.lblServerLinkId).equals(title)) {
|
||||
startActivity(new Intent(LoginActivity.this, ServerLinkActivity.class));
|
||||
}
|
||||
if (getString(R.string.lblDevOption).equals(title)) {
|
||||
startActivity(new Intent(LoginActivity.this, DeveloperOptionActivity.class));
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
//delete downloaded update file
|
||||
File file = new File(getApplicationContext().getFilesDir(), "app.apk");
|
||||
if(file.exists()) {
|
||||
boolean result = file.delete();
|
||||
if(!result){
|
||||
Toast.makeText(this, "Cannot delete downloaded update file", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
if(hasLogged && GlobalData.getSharedGlobalData().getUser() != null)
|
||||
return;//dipatch if has logged
|
||||
|
||||
|
||||
LocaleHelper.onCreate(getApplicationContext());
|
||||
setContentView(R.layout.new_login_activity);
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
|
||||
getWindow().getDecorView().setImportantForAutofill(
|
||||
View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
|
||||
}
|
||||
logo = (ImageView) findViewById(R.id.logoMobile);
|
||||
loginHeader = findViewById(R.id.loginHeader);
|
||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setTitle("");
|
||||
setSupportActionBar(toolbar);
|
||||
loginImpl = new LoginImpl(this);
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
//Check location permission whether to show educational UI about permission or not
|
||||
if (Global.ENABLE_LOC_PERMISSION_UI) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED &&
|
||||
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_DENIED) {
|
||||
showLocationPermissionInformativeUI();
|
||||
} else {
|
||||
Utility.checkPermissionGranted(LoginActivity.this);
|
||||
}
|
||||
} else {
|
||||
if (PermissionChecker.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PermissionChecker.PERMISSION_DENIED &&
|
||||
PermissionChecker.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PermissionChecker.PERMISSION_DENIED) {
|
||||
showLocationPermissionInformativeUI();
|
||||
} else {
|
||||
Utility.checkPermissionGranted(LoginActivity.this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Utility.checkPermissionGranted(LoginActivity.this);
|
||||
}
|
||||
|
||||
ObscuredSharedPreferences sharedPreferences = ObscuredSharedPreferences.getPrefs(this,
|
||||
LOGIN_PREFERENCES, Context.MODE_PRIVATE);
|
||||
if (sharedPreferences.contains("is_expired") && sharedPreferences.getBoolean("is_expired", false)) {
|
||||
sharedPreferences.edit().putBoolean("is_expired", false).apply();
|
||||
FileSyncHelper.senderID = 0;
|
||||
FileSyncHelper.startFileSync(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (null != loginImpl) { // Penjagaan ketika masuk kembali ke APP (kejadian null saat di collection)
|
||||
if (loginImpl.isRooted()) {
|
||||
DialogManager.showRootAlert(this, getApplicationContext());
|
||||
}
|
||||
|
||||
if (loginImpl.checkPlayServices(this)) {
|
||||
// Then we're good to go!
|
||||
}
|
||||
}
|
||||
|
||||
DialogManager.showTimeProviderAlert(this);
|
||||
|
||||
if (Helper.isDevEnabled(this) && GlobalData.getSharedGlobalData().isDevEnabled() && !GlobalData.getSharedGlobalData().isByPassDeveloper()) {
|
||||
DialogManager.showTurnOffDevMode(this);
|
||||
}
|
||||
|
||||
if(hasLogged)
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
//prevent from activity destroyed before dialog closed
|
||||
if(dataContext != null){
|
||||
DefaultLoginModel defaultLoginModel = (DefaultLoginModel)dataContext;
|
||||
defaultLoginModel.closeProgress();
|
||||
}
|
||||
|
||||
if(hasLogged)
|
||||
return;
|
||||
|
||||
if (loginImpl.getLocationManager() != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
} else {
|
||||
loginImpl.removeUpdateLocation();
|
||||
}
|
||||
} else {
|
||||
loginImpl.removeUpdateLocation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
Context context = newBase;
|
||||
Locale locale;
|
||||
try{
|
||||
locale = new Locale(LocaleHelper.getLanguage(newBase));
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} catch (Exception e) {
|
||||
locale = new Locale(Locale.getDefault().getLanguage());
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} finally {
|
||||
super.attachBaseContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
PackageInfo pInfo;
|
||||
try {
|
||||
new RefreshToken(getBaseContext()).onTokenRefresh();
|
||||
} catch (Exception e){
|
||||
FireCrash.log(e);
|
||||
}
|
||||
try {
|
||||
pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
|
||||
Global.APP_VERSION = pInfo.versionName;
|
||||
Global.BUILD_VERSION = pInfo.versionCode;
|
||||
|
||||
} catch (NameNotFoundException e) {
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
TextView tvAppVersion = (TextView) findViewById(R.id.contentVersion);
|
||||
String versioning = getString(R.string.app_name) + " v." + Global.APP_VERSION;
|
||||
tvAppVersion.setText(versioning);
|
||||
|
||||
loginImpl.initializePreferences();
|
||||
loginPreferences = loginImpl.getLoginPreferences();
|
||||
|
||||
setModel(getNewDefaultLoginModel(this));
|
||||
attachEventListener();
|
||||
|
||||
String language = LocaleHelper.getLanguage(this);
|
||||
LocaleHelper.setLocale(this,language);
|
||||
|
||||
TextView androidId = (TextView) findViewById(R.id.androidId);
|
||||
TextView divider = (TextView) findViewById(R.id.divider);
|
||||
final String android_id;
|
||||
if(Build.VERSION.SDK_INT > 28){
|
||||
android_id = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||
androidId.setVisibility(View.VISIBLE);
|
||||
divider.setVisibility(View.VISIBLE);
|
||||
}else {
|
||||
android_id = "";
|
||||
androidId.setVisibility(View.GONE);
|
||||
divider.setVisibility(View.GONE);
|
||||
}
|
||||
androidId.setText(android_id);
|
||||
androidId.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("Clip", android_id);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(getApplicationContext(),getString(R.string.copied),Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract DefaultLoginModel getNewDefaultLoginModel(Context context);
|
||||
|
||||
private void attachEventListener() {
|
||||
loginButton = (Button) findViewById(R.id.btnLogin);
|
||||
final CheckBox checkRememberMe = (CheckBox) findViewById(R.id.checkRememberMe);
|
||||
final EditText editUserId = (EditText) findViewById(R.id.txtUser);
|
||||
final EditText editPassword = (EditText) findViewById(R.id.txtPassword);
|
||||
|
||||
editUserId.setText(loginPreferences.getString(DefaultLoginModel.LOGIN_PREFERENCES_USERNAME, getString(R.string.txtempty)));
|
||||
editPassword.setText(loginPreferences.getString(DefaultLoginModel.LOGIN_PREFERENCES_PASSWORD, getString(R.string.txtempty)));
|
||||
checkRememberMe.setChecked(loginPreferences.getBoolean(DefaultLoginModel.LOGIN_PREFERENCES_REMEMBER_ME, false));
|
||||
if (checkRememberMe.isChecked()) {
|
||||
getModel().setRememberMe(true);
|
||||
}
|
||||
getModel().setUsername(editUserId.getText().toString());
|
||||
getModel().setPassword(editPassword.getText().toString());
|
||||
|
||||
loginButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (loginButton.getText().equals(txtDevModeOn) || loginButton.getText().equals(txtDevModeOnId)) {
|
||||
ObscuredSharedPreferences.Editor sharedPrefEditor = loginImpl.getSharedPref().edit();
|
||||
sharedPrefEditor.putBoolean("IS_DEV", true);
|
||||
sharedPrefEditor.commit();
|
||||
Global.IS_DEV = true;
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
enableMenuItem(true);
|
||||
editPassword.setText("");
|
||||
}
|
||||
});
|
||||
} else if (loginButton.getText().equals(txtDevModeOff) || loginButton.getText().equals(txtDevModeOffId)) {
|
||||
ObscuredSharedPreferences.Editor sharedPrefEditor = loginImpl.getSharedPref().edit();
|
||||
sharedPrefEditor.putBoolean("IS_DEV", false);
|
||||
sharedPrefEditor.commit();
|
||||
Global.IS_DEV = false;
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
enableMenuItem(false);
|
||||
editPassword.setText("");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
getModel().login();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
editUserId.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
getModel().setUsername(s.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
//EMPTY
|
||||
}
|
||||
});
|
||||
|
||||
editPassword.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
getModel().setPassword(s.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
String devMode = editPassword.getText().toString().trim();
|
||||
if (devMode != null && devMode.length() > 0 && devMode.equals(DevModeEnable) && loginImpl.isCan_access_developer_mode()) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loginButton.setText(getString(R.string.enableDevMode));
|
||||
}
|
||||
});
|
||||
} else if (devMode != null && devMode.length() > 0 && devMode.equals(DevModeDisable)) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loginButton.setText(getString(R.string.disableDevMode));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loginButton.setText(getString(R.string.btnLogin));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
checkRememberMe.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
getModel().setRememberMe(isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultLoginModel getModel() {
|
||||
return (DefaultLoginModel) dataContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModel(DefaultLoginModel model) {
|
||||
dataContext = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
switch (requestCode) {
|
||||
case Utility.REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: {
|
||||
if (Utility.checkPermissionResult(LoginActivity.this, permissions, grantResults)) {
|
||||
loginImpl.bindLocationListener();
|
||||
if (Global.ENABLE_LOC_PERMISSION_UI) {
|
||||
getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int color;
|
||||
protected void applyColorTheme(DynamicTheme dynamicTheme){//apply color set to views
|
||||
String commonBgColor = ThemeUtility.getColorItemValue(dynamicTheme,"bg_solid");
|
||||
String btnNormalColor = ThemeUtility.getColorItemValue(dynamicTheme,"btn_bg_normal");
|
||||
String btnPressedColor = ThemeUtility.getColorItemValue(dynamicTheme,"btn_bg_pressed");
|
||||
color = Color.parseColor(commonBgColor);
|
||||
ThemeUtility.setToolbarColor(toolbar,color);
|
||||
ThemeUtility.setStatusBarColor(this,color);
|
||||
ThemeUtility.setViewBackground(loginHeader,color);
|
||||
ThemeUtility.setViewBackground(loginButton,color);
|
||||
|
||||
//create color state list for button states
|
||||
int[][] btnstates = new int[][] {
|
||||
new int[] { android.R.attr.state_pressed}, // pressed
|
||||
new int[] {} // normal
|
||||
};
|
||||
|
||||
int[] btncolorlist = new int[]{
|
||||
Color.parseColor(btnPressedColor),
|
||||
Color.parseColor(btnNormalColor)
|
||||
};
|
||||
ColorStateList btnColorStateList = new ColorStateList(btnstates,btncolorlist);
|
||||
ThemeUtility.setViewBackground(loginButton,btnColorStateList);
|
||||
}
|
||||
|
||||
protected void fetchConfig() {
|
||||
final FirebaseRemoteConfig remoteConfig = FirebaseRemoteConfig.getInstance();
|
||||
FirebaseRemoteConfigSettings remoteConfigSettings = new FirebaseRemoteConfigSettings.Builder()
|
||||
.build();
|
||||
|
||||
defaultConfig = new HashMap<>();
|
||||
defaultConfig.put("cipher_unsupported_device", Global.SQLITE_CIPHER_UNSUPPORTED);
|
||||
|
||||
remoteConfig.setConfigSettingsAsync(remoteConfigSettings);
|
||||
remoteConfig.setDefaultsAsync(defaultConfig);
|
||||
remoteConfig.fetch().addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (!task.isComplete() && !task.isSuccessful())
|
||||
return;
|
||||
|
||||
remoteConfig.activate();
|
||||
GlobalData.getSharedGlobalData().setRemoteConfig(remoteConfig);
|
||||
|
||||
String sqliteCipherException = remoteConfig.getString("cipher_unsupported_device");
|
||||
Global.IS_DBENCRYPT = (!sqliteCipherException.contains(Build.MODEL)) && Global.IS_DBENCRYPT;
|
||||
}
|
||||
});
|
||||
|
||||
GlobalData.getSharedGlobalData().setRemoteConfig(remoteConfig);
|
||||
}
|
||||
|
||||
public void showLocationPermissionInformativeUI(){
|
||||
locPermissionFragment = new LocationPermissionInformationFragment();
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.login_activity,locPermissionFragment)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (Global.ENABLE_LOC_PERMISSION_UI && null != locPermissionFragment && locPermissionFragment.isVisible()) {
|
||||
Toast.makeText(this ,R.string.allow_all_permission, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> defaultConfig;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import com.adins.mss.base.commons.AppInfo;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.foundation.dialog.DialogManager;
|
||||
|
||||
/**
|
||||
* Created by kusnendi.muhamad on 03/08/2017.
|
||||
*/
|
||||
|
||||
public abstract class MssFragmentActivity extends AppCompatActivity implements LocationListener,
|
||||
AdapterView.OnItemClickListener, AppInfo {
|
||||
|
||||
protected LocationManager mLocation;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
bindLocationListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mLocation != null) {
|
||||
mLocation.removeUpdates(this);
|
||||
if (mLocation != null) {
|
||||
mLocation = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
//Check GPS Location Setting
|
||||
// DialogManager.showGPSAlert(this);
|
||||
|
||||
if (mLocation == null) {
|
||||
bindLocationListener();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
if (location != null)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (location.isFromMockProvider())
|
||||
DialogManager.showMockDialog(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
DialogManager.closeGPSAlert();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
DialogManager.showGPSAlert(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAppVersion(NewMainActivity activity) {
|
||||
}
|
||||
|
||||
public void bindLocationListener() {
|
||||
mLocation = (LocationManager) getSystemService(LOCATION_SERVICE);
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
Utility.checkPermissionGranted(this);
|
||||
return;
|
||||
} else {
|
||||
if (mLocation.getAllProviders().contains(LocationManager.GPS_PROVIDER))
|
||||
mLocation.requestLocationUpdates(LocationManager.GPS_PROVIDER, 15 * 1000L, 10f, this);
|
||||
}
|
||||
} else {
|
||||
if (mLocation.getAllProviders().contains(LocationManager.GPS_PROVIDER))
|
||||
mLocation.requestLocationUpdates(LocationManager.GPS_PROVIDER, 15 * 1000L, 10f, this);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO: handle exception
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.adins.mss.base.api.ChangePasswordApi;
|
||||
import com.adins.mss.base.api.ChangePasswordApiCallback;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.login.DefaultLoginModel;
|
||||
import com.adins.mss.base.models.ChangePasswordRequestModel;
|
||||
import com.adins.mss.base.syncfile.FileSyncHelper;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.dao.User;
|
||||
import com.adins.mss.foundation.db.dataaccess.UserDataAccess;
|
||||
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||
|
||||
public class NewChangePasswordActivity extends AppCompatActivity {
|
||||
|
||||
private EditText currentPassword;
|
||||
private EditText newPassword;
|
||||
private EditText retypePassword;
|
||||
private Button changePassword;
|
||||
private FirebaseAnalytics screenName;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
screenName = FirebaseAnalytics.getInstance(this);
|
||||
setContentView(R.layout.new_change_password_activity);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setTitleTextColor(getResources().getColor(R.color.fontColorWhite));
|
||||
toolbar.setTitle(getResources().getString(R.string.title_mn_resetpassword));
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
String pwdExp = this.getIntent().getStringExtra(DefaultLoginModel.PWD_EXP);
|
||||
try {
|
||||
if (pwdExp.equals("1")) {
|
||||
Toast.makeText(NewChangePasswordActivity.this, getString(R.string.password_expired),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
// TODO: handle exception
|
||||
}
|
||||
|
||||
|
||||
currentPassword = (EditText) findViewById(R.id.currentPassword);
|
||||
newPassword = (EditText) findViewById(R.id.newPassword);
|
||||
retypePassword = (EditText) findViewById(R.id.retypePassword);
|
||||
changePassword = (Button) findViewById(R.id.changePassword);
|
||||
|
||||
changePassword.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (newPassword.getText() == null ||
|
||||
newPassword.getText().toString().equals("")) {
|
||||
newPassword.setError(getString(R.string.new_password_mandatory));
|
||||
return;
|
||||
}
|
||||
if (!newPassword.getText().toString().equals(retypePassword.getText().toString())) {
|
||||
Toast.makeText(NewChangePasswordActivity.this, getString(R.string.new_password_equal), Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
ChangePasswordRequestModel request = new ChangePasswordRequestModel();
|
||||
request.setUuid_user(GlobalData.getSharedGlobalData().getUser().getUuid_user());
|
||||
request.setOld_password(currentPassword.getText().toString());
|
||||
request.setNew_password(newPassword.getText().toString());
|
||||
request.setAudit(GlobalData.getSharedGlobalData().getAuditData());
|
||||
|
||||
ChangePasswordApi api = new ChangePasswordApi(NewChangePasswordActivity.this);
|
||||
api.setCallback(new ChangePasswordApiCallback() {
|
||||
@Override
|
||||
public void onFailed(String message) {
|
||||
try {
|
||||
Toast.makeText(NewChangePasswordActivity.this, getString(R.string.warning_capital) + ": " + message, Toast.LENGTH_LONG).show();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
Toast.makeText(NewChangePasswordActivity.this, "Change Password Error", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Toast.makeText(NewChangePasswordActivity.this, getString(R.string.password_changed), Toast.LENGTH_LONG).show();
|
||||
User user = GlobalData.getSharedGlobalData().getUser();
|
||||
user.setPassword(newPassword.getText().toString());
|
||||
UserDataAccess.addOrReplace(NewChangePasswordActivity.this, user);
|
||||
// goToSynchronize();
|
||||
Global.syncIntent = null;
|
||||
finish();
|
||||
clear();
|
||||
}
|
||||
});
|
||||
|
||||
api.execute(request);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
screenName.setCurrentScreen(this, getString(R.string.screen_name_change_password), null);
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
currentPassword.setText("");
|
||||
newPassword.setText("");
|
||||
retypePassword.setText("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
//
|
||||
}
|
||||
|
||||
private void goToSynchronize() {
|
||||
if (Global.syncIntent != null) {
|
||||
Intent syncIntent = Global.syncIntent;
|
||||
startActivity(syncIntent);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,590 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Vibrator;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.adins.mss.base.checkin.CheckInManager;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.dynamicform.Constant;
|
||||
import com.adins.mss.base.util.EventBusHelper;
|
||||
import com.adins.mss.base.util.LocaleHelper;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.dao.PrintDate;
|
||||
import com.adins.mss.dao.PrintResult;
|
||||
import com.adins.mss.dao.ReceiptVoucher;
|
||||
import com.adins.mss.dao.TaskH;
|
||||
import com.adins.mss.foundation.UserHelp.UserHelp;
|
||||
import com.adins.mss.foundation.db.dataaccess.PrintDateDataAccess;
|
||||
import com.adins.mss.foundation.db.dataaccess.PrintResultDataAccess;
|
||||
import com.adins.mss.foundation.db.dataaccess.ReceiptVoucherDataAccess;
|
||||
import com.adins.mss.foundation.db.dataaccess.TaskHDataAccess;
|
||||
import com.adins.mss.foundation.dialog.NiftyDialogBuilder;
|
||||
import com.adins.mss.foundation.location.UpdateMenuIcon;
|
||||
import com.adins.mss.foundation.print.AB200MPrintManager;
|
||||
import com.adins.mss.foundation.print.AbstractPrintManager;
|
||||
import com.adins.mss.foundation.print.PrintManagerListener;
|
||||
import com.adins.mss.foundation.print.rv.InputRVNumberActivity;
|
||||
import com.adins.mss.foundation.print.rv.syncs.SyncRVRequest;
|
||||
import com.adins.mss.foundation.print.rv.syncs.SyncRVResponse;
|
||||
import com.adins.mss.foundation.print.rv.syncs.SyncRVTask;
|
||||
import com.adins.mss.foundation.print.rv.syncs.SyncRvListener;
|
||||
import com.androidquery.AQuery;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import zj.com.cn.bluetooth.sdk.DeviceListActivity;
|
||||
|
||||
import static com.adins.mss.constant.Global.SHOW_USERHELP_DELAY_DEFAULT;
|
||||
|
||||
/**
|
||||
* Created by winy.firdasari on 30/01/2015.
|
||||
*/
|
||||
|
||||
public class PrintActivity extends AppCompatActivity implements View.OnClickListener, PrintManagerListener {
|
||||
public static final String TASKS = "PrintActivitiy.TASKS";
|
||||
public static final String UUID_TASKH = "uuid_taskh";
|
||||
public static final String COUNT_RV_NUMBER = "count_rv_number";
|
||||
public static final String SOURCE_TASK = "source";
|
||||
public static final int FROM_ACTIVITY_RV_NUMBER = 1;
|
||||
// Intent request codes
|
||||
private static final int REQUEST_CONNECT_DEVICE = 1;
|
||||
protected static List<PrintResult> listOfPrint;
|
||||
private AbstractPrintManager printManager;
|
||||
private TextView lblPrinterStatus;
|
||||
private Button btnConnect;
|
||||
private Button btnPrint;
|
||||
private String uuidTaskH;
|
||||
private boolean isPrintDeposit;
|
||||
private AQuery query;
|
||||
private TaskH taskH;
|
||||
private String printerName = "-";
|
||||
private String source;
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
|
||||
public static void setListOfPrint(List<PrintResult> listOfPrint) {
|
||||
PrintActivity.listOfPrint = listOfPrint;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.print_activity);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(com.adins.mss.base.R.id.toolbar);
|
||||
toolbar.setTitle(getString(R.string.title_print));
|
||||
toolbar.setTitleTextColor(getResources().getColor(com.adins.mss.base.R.color.fontColorWhite));
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ACRA.getErrorReporter().putCustomData("LAST_CLASS_ACCESSED", getClass().getSimpleName());
|
||||
|
||||
query = new AQuery(this);
|
||||
|
||||
lblPrinterStatus = (TextView) findViewById(R.id.lblPrinterStatus);
|
||||
btnConnect = (Button) findViewById(R.id.btnConnect);
|
||||
btnPrint = (Button) findViewById(R.id.btnPrint);
|
||||
|
||||
if (btnConnect != null) {
|
||||
btnConnect.setOnClickListener(this);
|
||||
btnPrint.setOnClickListener(this);
|
||||
}
|
||||
|
||||
//bong 8 may 15 - get print result from db
|
||||
String taskId = this.getIntent().getStringExtra("taskId");
|
||||
isPrintDeposit = getIntent().getBooleanExtra("isPrintDeposit", false);
|
||||
source = this.getIntent().getStringExtra("source");
|
||||
|
||||
taskH = TaskHDataAccess.getOneTaskHeader(getApplicationContext(), taskId);
|
||||
List<PrintResult> results;
|
||||
|
||||
uuidTaskH = taskH != null ? taskH.getUuid_task_h() : taskId;
|
||||
results = PrintResultDataAccess.getAll(getApplicationContext(), uuidTaskH);
|
||||
|
||||
if (results == null || results.isEmpty()) {
|
||||
Toast.makeText(this, getString(R.string.printResultNull), Toast.LENGTH_SHORT).show();
|
||||
this.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
printManager = new AB200MPrintManager(this, results);
|
||||
Constant.setListOfPrintItem(results);
|
||||
|
||||
updateUI(printManager.isConnected());
|
||||
|
||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (!mBluetoothAdapter.isEnabled()) {
|
||||
Toast.makeText(this, getString(R.string.bt_off), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
|
||||
parent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(!UserHelp.isActive)
|
||||
UserHelp.showAllUserHelp(PrintActivity.this,
|
||||
PrintActivity.this.getClass().getSimpleName());
|
||||
}
|
||||
}, SHOW_USERHELP_DELAY_DEFAULT);
|
||||
}
|
||||
});
|
||||
return super.onCreateView(parent, name, context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
Context context = newBase;
|
||||
Locale locale;
|
||||
try{
|
||||
locale = new Locale(GlobalData.getSharedGlobalData().getLocale());
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} catch (Exception e) {
|
||||
locale = new Locale(LocaleHelper.ENGLSIH);
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} finally {
|
||||
super.attachBaseContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (printManager != null) {
|
||||
if (printManager.isConnected()) {
|
||||
try {
|
||||
printManager.disconnect();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
printManager.releaseResources();
|
||||
}
|
||||
|
||||
query = null;
|
||||
printManager = null;
|
||||
setListOfPrint(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!query.id(R.id.btnConnect).getButton().isEnabled() ||
|
||||
!query.id(R.id.btnPrint).getButton().isEnabled()) {
|
||||
Toast.makeText(this, "cannot close, please wait...", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateUI(boolean isConnected) {
|
||||
if (btnConnect != null) {
|
||||
if (isConnected) {
|
||||
lblPrinterStatus.setText(getString(R.string.connected));
|
||||
btnConnect.setText(getString(R.string.mnDisconnect));
|
||||
btnPrint.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
lblPrinterStatus.setText(getString(R.string.not_connected));
|
||||
btnConnect.setText(getString(R.string.mnConnect));
|
||||
btnPrint.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater menuInflater = getMenuInflater();
|
||||
menuInflater.inflate(com.adins.mss.base.R.menu.main_menu, menu);
|
||||
mainMenu = menu;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
updateMenuIcon(Global.isGPS);
|
||||
|
||||
if(Global.ENABLE_USER_HELP &&
|
||||
(Global.userHelpGuide.get(PrintActivity.this.getClass().getSimpleName())!=null) ||
|
||||
Global.userHelpDummyGuide.get(PrintActivity.this.getClass().getSimpleName()) != null){
|
||||
menu.findItem(com.adins.mss.base.R.id.mnGuide).setVisible(true);
|
||||
}
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
private static Menu mainMenu;
|
||||
|
||||
public static void updateMenuIcon(boolean isGPS) {
|
||||
UpdateMenuIcon uItem = new UpdateMenuIcon();
|
||||
uItem.updateGPSIcon(mainMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if (id == com.adins.mss.base.R.id.mnGPS && Global.LTM != null) {
|
||||
if (Global.LTM.getIsConnected()) {
|
||||
Global.LTM.removeLocationListener();
|
||||
Global.LTM.connectLocationClient();
|
||||
} else {
|
||||
CheckInManager.startGPSTracking(getApplicationContext());
|
||||
}
|
||||
Animation a = AnimationUtils.loadAnimation(this, com.adins.mss.base.R.anim.gps_rotate);
|
||||
findViewById(com.adins.mss.base.R.id.mnGPS).startAnimation(a);
|
||||
}
|
||||
|
||||
if(id==R.id.mnGuide && !Global.BACKPRESS_RESTRICTION){
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
UserHelp.showAllUserHelp(PrintActivity.this, PrintActivity.this.getClass().getSimpleName());
|
||||
}
|
||||
}, SHOW_USERHELP_DELAY_DEFAULT);
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
protected void connect() {
|
||||
try {
|
||||
printManager.connect();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, getResources().getString(R.string.failed_to_connect), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
protected void connect(BluetoothDevice device) {
|
||||
try {
|
||||
printManager.connect();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, getResources().getString(R.string.failed_to_connect), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
protected void disconnect() {
|
||||
try {
|
||||
printManager.disconnect();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v == btnConnect) {
|
||||
if (!btnConnect.getText().equals(getResources().getString(R.string.connecting))) {
|
||||
if (printManager.isConnected()) {
|
||||
disconnect();
|
||||
} else {
|
||||
Intent serverIntent = new Intent(PrintActivity.this, DeviceListActivity.class);
|
||||
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
new PrintAsync().execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(String deviceName) {
|
||||
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
||||
v.vibrate(400);
|
||||
|
||||
query.id(R.id.tv_device_name).text(deviceName);
|
||||
query.id(R.id.btnConnect).enabled(true);
|
||||
updateUI(printManager.isConnected());
|
||||
Toast.makeText(this, getString(R.string.connected), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectFailed() {
|
||||
onDisconnect();
|
||||
showErrorDialog(ErrorType.PRINT_FAILED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnecting() {
|
||||
query.id(R.id.btnConnect).enabled(false).text(R.string.connecting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect() {
|
||||
query.id(R.id.tv_device_name).text("-");
|
||||
printerName = "-";
|
||||
query.id(R.id.btnConnect).enabled(true);
|
||||
updateUI(printManager.isConnected());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
// Get the device MAC address
|
||||
String address = data.getExtras().getString(
|
||||
DeviceListActivity.EXTRA_DEVICE_ADDRESS);
|
||||
// Get the BLuetoothDevice object
|
||||
if (BluetoothAdapter.checkBluetoothAddress(address)) {
|
||||
BluetoothDevice device = mBluetoothAdapter
|
||||
.getRemoteDevice(address);
|
||||
// Attempt to connect to the device
|
||||
connect(device);
|
||||
} else {
|
||||
showErrorDialog(ErrorType.PRINT_FAILED);
|
||||
}
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void syncRvNumber() {
|
||||
String uuidUser = GlobalData.getSharedGlobalData().getUser().getUuid_user();
|
||||
SyncRVRequest request = new SyncRVRequest();
|
||||
request.setLastDtmCrt(ReceiptVoucherDataAccess.getLastDate(this, uuidUser));
|
||||
|
||||
SyncRVTask task = new SyncRVTask(this, request, new SyncRvListener() {
|
||||
ProgressDialog dialog;
|
||||
|
||||
@Override
|
||||
public void onProgress() {
|
||||
dialog = ProgressDialog.show(PrintActivity.this, "Sync RV Number", getString(R.string.please_wait), true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(SyncRVResponse response) {
|
||||
if (dialog != null && dialog.isShowing()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
if (response.getErrorMessage() != null) {
|
||||
showErrorDialog(ErrorType.SYNC_RV_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(SyncRVResponse response) {
|
||||
if (dialog != null && dialog.isShowing()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
List<ReceiptVoucher> rvNumbers = response.getListReceiptVoucher();
|
||||
|
||||
if (rvNumbers != null && !rvNumbers.isEmpty()) {
|
||||
try {
|
||||
ReceiptVoucherDataAccess.addNewReceiptVoucher(PrintActivity.this,
|
||||
GlobalData.getSharedGlobalData().getUser().getUuid_user(),
|
||||
rvNumbers);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
ACRA.getErrorReporter().putCustomData("errorRV", e.getMessage());
|
||||
ACRA.getErrorReporter().handleSilentException(new Exception("Error: Insert RV Error. " + e.getMessage()));
|
||||
Toast.makeText(PrintActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
openInputRVActivity();
|
||||
|
||||
}
|
||||
});
|
||||
task.execute();
|
||||
}
|
||||
|
||||
private void openInputRVActivity() {
|
||||
Intent intent = new Intent(PrintActivity.this, InputRVNumberActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent.putExtra(UUID_TASKH, uuidTaskH);
|
||||
intent.putExtra(SOURCE_TASK, source);
|
||||
startActivityForResult(intent, FROM_ACTIVITY_RV_NUMBER);
|
||||
}
|
||||
|
||||
private void showErrorDialog(ErrorType errorType) {
|
||||
if (isPrintDeposit) return;
|
||||
if (taskH != null && taskH.getPrint_count() != null && taskH.getPrint_count() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final NiftyDialogBuilder dialog = NiftyDialogBuilder.getInstance(this)
|
||||
.isCancelable(true)
|
||||
.isCancelableOnTouchOutside(false);
|
||||
|
||||
switch (errorType) {
|
||||
case PRINT_FAILED:
|
||||
dialog.withTitle(getString(R.string.connect_failed))
|
||||
.withMessage(R.string.reconnect_message)
|
||||
.withButton1Text(getString(R.string.try_again))
|
||||
.setButton1Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.dismiss();
|
||||
Intent serverIntent = new Intent(PrintActivity.this, DeviceListActivity.class);
|
||||
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
|
||||
}
|
||||
})
|
||||
.withButton2Text(getString(R.string.input_rv))
|
||||
.setButton2Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.dismiss();
|
||||
syncRvNumber();
|
||||
}
|
||||
});
|
||||
break;
|
||||
case SYNC_RV_FAILED:
|
||||
boolean isRvNumberEmpty = ReceiptVoucherDataAccess.getByStatus(this,
|
||||
GlobalData.getSharedGlobalData().getUser().getUuid_user(),
|
||||
ReceiptVoucherDataAccess.STATUS_NEW).isEmpty();
|
||||
dialog.withTitle(getString(R.string.error_capital))
|
||||
.withMessage(R.string.sync_rv_failed)
|
||||
.withButton1Text(getString(R.string.try_again))
|
||||
.setButton1Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.dismiss();
|
||||
syncRvNumber();
|
||||
}
|
||||
});
|
||||
if (!isRvNumberEmpty) {
|
||||
dialog.withButton2Text(getString(R.string.btnNext))
|
||||
.setButton2Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.dismiss();
|
||||
openInputRVActivity();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dialog.withButton2Text(getString(R.string.btnClose))
|
||||
.setButton2Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public enum ErrorType {
|
||||
PRINT_FAILED,
|
||||
SYNC_RV_FAILED
|
||||
}
|
||||
|
||||
public class PrintAsync extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
public PrintAsync() {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
|
||||
query.id(R.id.btnPrint).enabled(false).text("Printing...");
|
||||
query.id(R.id.btnConnect).enabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
try {
|
||||
if (printManager.isConnected()) {
|
||||
if (printerName.toLowerCase().contains("sato")) {
|
||||
return printManager.printSato();
|
||||
} else {
|
||||
return printManager.print();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean aBoolean) {
|
||||
super.onPostExecute(aBoolean);
|
||||
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (aBoolean && printManager.isConnected() && printManager.isPrinterConnected()) {
|
||||
if (GlobalData.getSharedGlobalData().getApplication() == null) {
|
||||
NewMainActivity.InitializeGlobalDataIfError(getApplicationContext());
|
||||
}
|
||||
|
||||
if (GlobalData.getSharedGlobalData().getApplication().equals("MC") && !isPrintDeposit) {
|
||||
if (taskH != null) {
|
||||
int count = taskH.getPrint_count() == null ? 0 : taskH.getPrint_count();
|
||||
taskH.setPrint_count(count + 1);
|
||||
TaskHDataAccess.addOrReplace(PrintActivity.this, taskH);
|
||||
}
|
||||
|
||||
PrintDate taskSubmit = new PrintDate();
|
||||
taskSubmit.setDtm_print(new Date());
|
||||
taskSubmit.setUuid_task_h(uuidTaskH);
|
||||
PrintDateDataAccess.addOrReplace(PrintActivity.this, taskSubmit);
|
||||
|
||||
EventBusHelper.post(taskSubmit);
|
||||
}
|
||||
|
||||
query.id(R.id.btnPrint).enabled(true).text(R.string.print);
|
||||
query.id(R.id.btnConnect).enabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
query.id(R.id.btnPrint).enabled(true).text(R.string.print);
|
||||
query.id(R.id.btnConnect).enabled(true);
|
||||
|
||||
Toast.makeText(PrintActivity.this, "Device is not connected to the printer", Toast.LENGTH_SHORT).show();
|
||||
try {
|
||||
showErrorDialog(ErrorType.PRINT_FAILED);
|
||||
printManager.disconnect();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.dao.PrintResult;
|
||||
import com.adins.mss.dao.TaskH;
|
||||
import com.adins.mss.foundation.db.dataaccess.PrintResultDataAccess;
|
||||
import com.adins.mss.foundation.db.dataaccess.TaskHDataAccess;
|
||||
import com.adins.mss.foundation.dialog.DialogManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by winy.firdasari on 30/01/2015.
|
||||
*/
|
||||
|
||||
public class PrintTask extends AsyncTask<String, Void, List<PrintResult>> {
|
||||
private ProgressDialog progressDialog;
|
||||
private String errMessage = null;
|
||||
private Activity activity;
|
||||
private String messageWait;
|
||||
private String messageEmpty;
|
||||
private String taskId;
|
||||
|
||||
//inijiniunnij dasfasfs
|
||||
|
||||
public PrintTask(Activity activity) {
|
||||
this.activity = activity;
|
||||
this.messageWait = activity.getString(R.string.progressWait);
|
||||
this.messageEmpty = activity.getString(R.string.msgNoPrintItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
progressDialog = ProgressDialog.show(this.activity, "", this.messageWait, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected List<PrintResult> doInBackground(String... params) {
|
||||
List<PrintResult> result = null;
|
||||
|
||||
try {
|
||||
String taskId = params[0];
|
||||
this.taskId = taskId;
|
||||
|
||||
//bong 7 may 15 - asumsi data print result di lokal sudah siap untuk di-print
|
||||
TaskH taskH = TaskHDataAccess.getOneTaskHeader(activity, taskId);
|
||||
result = PrintResultDataAccess.getAll(activity, taskH.getUuid_task_h());
|
||||
// FormManager formManager = new FormManager();
|
||||
// result = formManager.getReadyPrintItem(activity, taskId);
|
||||
} catch (Exception ex) {
|
||||
if (Global.IS_DEV)
|
||||
ex.printStackTrace();
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
errMessage = ex.getMessage();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<PrintResult> result) {
|
||||
if (progressDialog.isShowing()) {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (errMessage != null) {
|
||||
DialogManager.showAlert(activity, DialogManager.TYPE_ERROR, errMessage, activity.getString(R.string.test_label));
|
||||
} else if (result == null || result.size() == 0) {
|
||||
DialogManager.showAlert(activity, DialogManager.TYPE_INFO, messageEmpty, activity.getString(R.string.test_label));
|
||||
} else {
|
||||
PrintActivity.setListOfPrint(result);
|
||||
Intent i = new Intent(this.activity, PrintActivity.class);
|
||||
this.activity.startActivity(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.util.LocaleHelper;
|
||||
import com.adins.mss.foundation.dialog.DialogManager;
|
||||
import com.adins.mss.foundation.security.storepreferences.ObscuredSharedPreferences;
|
||||
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class ServerLinkActivity extends AppCompatActivity implements OnClickListener {
|
||||
|
||||
private FirebaseAnalytics screenName;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.new_server_link_activity);
|
||||
|
||||
screenName = FirebaseAnalytics.getInstance(this);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setTitleTextColor(getResources().getColor(R.color.fontColorWhite));
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ACRA.getErrorReporter().putCustomData("LAST_CLASS_ACCESSED", getClass().getSimpleName());
|
||||
EditText txtServerLink = (EditText) findViewById(R.id.txtServerLink);
|
||||
txtServerLink.setText(GlobalData.getSharedGlobalData().getUrlMain());
|
||||
|
||||
Button btnLogin = (Button) findViewById(R.id.btnSaveLink);
|
||||
btnLogin.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
ServerLinkActivity.this.finish();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
|
||||
super.onResume();
|
||||
//Set Firebase screen name
|
||||
screenName.setCurrentScreen(this, getString(R.string.screen_name_server_link), null);
|
||||
|
||||
try {
|
||||
DialogManager.showGPSAlert(this);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
Context context = newBase;
|
||||
Locale locale;
|
||||
try{
|
||||
locale = new Locale(GlobalData.getSharedGlobalData().getLocale());
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} catch (Exception e) {
|
||||
locale = new Locale(LocaleHelper.ENGLSIH);
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} finally {
|
||||
super.attachBaseContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
Button btn = (Button) v;
|
||||
int id = btn.getId();
|
||||
if (R.id.btnSaveLink == id) {
|
||||
EditText txtServerLink = (EditText) findViewById(R.id.txtServerLink);
|
||||
String serverLink = txtServerLink.getText().toString().trim();
|
||||
|
||||
|
||||
GlobalData.getSharedGlobalData().setUrlMain(serverLink);
|
||||
GlobalData.getSharedGlobalData().reloadUrl(this.getApplicationContext());
|
||||
|
||||
//Gigin ~ set URL Header Di Global.URL_HEADER tanpa "m/"
|
||||
ObscuredSharedPreferences sharedPref = ObscuredSharedPreferences.getPrefs(getApplicationContext(),
|
||||
"GlobalData", Context.MODE_PRIVATE);
|
||||
|
||||
ObscuredSharedPreferences.Editor sharedPrefEditor = sharedPref.edit();
|
||||
sharedPrefEditor.putString("URL_HEADER", serverLink);
|
||||
sharedPrefEditor.commit();
|
||||
|
||||
ServerLinkActivity.this.finish();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package com.adins.mss.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.adins.mss.base.dynamictheme.DynamicTheme;
|
||||
import com.adins.mss.base.dynamictheme.ThemeLoader;
|
||||
import com.adins.mss.base.synchronize.ProgressListener;
|
||||
import com.adins.mss.base.synchronize.SynchronizeView;
|
||||
import com.adins.mss.base.util.LocaleHelper;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Created by winy.firdasari on 05/01/2015.
|
||||
*/
|
||||
|
||||
public abstract class SynchronizeActivity extends AppCompatActivity implements ProgressListener, ThemeLoader.ColorSetLoaderCallback {
|
||||
|
||||
public Activity activity = this;
|
||||
private SynchronizeView views;
|
||||
|
||||
public SynchronizeActivity() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.new_synchronize_activity);
|
||||
ACRA.getErrorReporter().putCustomData("LAST_CLASS_ACCESSED", getClass().getSimpleName());
|
||||
views = new SynchronizeView(activity, getIntentMainMenu(), this);
|
||||
loadColorSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
Context context = newBase;
|
||||
Locale locale;
|
||||
try{
|
||||
locale = new Locale(GlobalData.getSharedGlobalData().getLocale());
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} catch (Exception e) {
|
||||
locale = new Locale(LocaleHelper.ENGLSIH);
|
||||
context = LocaleHelper.wrap(newBase, locale);
|
||||
} finally {
|
||||
super.attachBaseContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadColorSet(){
|
||||
ThemeLoader themeLoader = new ThemeLoader(this);
|
||||
themeLoader.loadSavedColorSet(this);
|
||||
}
|
||||
|
||||
protected abstract Intent getIntentMainMenu();
|
||||
|
||||
@Override
|
||||
public void onUpdatedValue(float progress) {
|
||||
views.progressUpdated(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSyncScheme(boolean value) {
|
||||
views.isSyncScheme = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSyncQuestion(boolean value) {
|
||||
views.isSyncQuestionSet = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSyncLookup(boolean value) {
|
||||
views.isSyncLookup = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSyncHoliday(boolean value) {
|
||||
views.isSyncHoliday = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSyncPaymentChannel(boolean value) {
|
||||
views.isSyncPaymentChannel = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHasLoaded(DynamicTheme dynamicTheme) {
|
||||
views.initialize();
|
||||
if(dynamicTheme != null && !dynamicTheme.getThemeItemList().isEmpty())
|
||||
views.applyColorTheme(dynamicTheme);
|
||||
views.publish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHasLoaded(DynamicTheme dynamicTheme, boolean needUpdate) {
|
||||
//EMPTY
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.adins.mss.base.about;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.adins.mss.base.R;
|
||||
import com.mikepenz.aboutlibraries.entity.Library;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author gigin.ginanjar
|
||||
*/
|
||||
public class AboutArrayAdapter extends ArrayAdapter<Library> {
|
||||
private Context mContext;
|
||||
private List<Library> libraries;
|
||||
|
||||
/**
|
||||
* Inisialisasi About Array Adapter
|
||||
*
|
||||
* @param context - Context
|
||||
* @param libraries - List of Libary
|
||||
*/
|
||||
public AboutArrayAdapter(Context context, List<Library> libraries) {
|
||||
super(context, R.layout.new_about_library_log, libraries);
|
||||
|
||||
this.mContext = context;
|
||||
if (libraries != null)
|
||||
this.libraries = libraries;
|
||||
else
|
||||
this.libraries = new ArrayList<Library>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return libraries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(getContext()).inflate(R.layout.new_about_library_log, parent, false);
|
||||
}
|
||||
((TextView) convertView.findViewById(R.id.libraryname)).setText(libraries.get(position).getLibraryName());
|
||||
((TextView) convertView.findViewById(R.id.librarycreator)).setText(libraries.get(position).getAuthor());
|
||||
((TextView) convertView.findViewById(R.id.libraryversion)).setText(libraries.get(position).getLibraryVersion());
|
||||
// ((TextView)convertView.findViewById(R.id.librarylicense)).setText(libraries.get(position).getLicense().getLicenseName());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
((TextView) convertView.findViewById(R.id.description)).setText(Html.fromHtml(libraries.get(position).getLibraryDescription(), Html.FROM_HTML_MODE_LEGACY));
|
||||
} else {
|
||||
((TextView) convertView.findViewById(R.id.description)).setText(Html.fromHtml(libraries.get(position).getLibraryDescription()));
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,411 @@
|
|||
package com.adins.mss.base.about.activity;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.adins.mss.base.GlobalData;
|
||||
import com.adins.mss.base.R;
|
||||
import com.adins.mss.base.about.AboutArrayAdapter;
|
||||
import com.adins.mss.base.about.activity.JsonVersionResponse.ListValue;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.update.DownloadUpdate;
|
||||
import com.adins.mss.base.util.GsonHelper;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.foundation.UserHelp.UserHelp;
|
||||
import com.adins.mss.foundation.db.dataaccess.GeneralParameterDataAccess;
|
||||
import com.adins.mss.foundation.dialog.NiftyDialogBuilder;
|
||||
import com.adins.mss.foundation.formatter.Tool;
|
||||
import com.adins.mss.foundation.http.HttpConnectionResult;
|
||||
import com.adins.mss.foundation.http.HttpCryptedConnection;
|
||||
import com.adins.mss.foundation.http.MssRequestType;
|
||||
import com.androidquery.AQuery;
|
||||
import com.github.jjobes.slidedatetimepicker.SlidingTabLayout;
|
||||
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||
import com.google.firebase.perf.FirebasePerformance;
|
||||
import com.google.firebase.perf.metrics.HttpMetric;
|
||||
import com.mikepenz.aboutlibraries.Libs;
|
||||
import com.mikepenz.aboutlibraries.entity.Library;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.adins.mss.constant.Global.SHOW_USERHELP_DELAY_DEFAULT;
|
||||
|
||||
/**
|
||||
* @author gigin.ginanjar
|
||||
*/
|
||||
public class AboutActivity extends Fragment {
|
||||
private static ArrayList<Library> library;
|
||||
private static int flag;
|
||||
public Libs libs;
|
||||
AQuery query;
|
||||
TextView appDesc;
|
||||
TextView appName;
|
||||
ListView listAbout;
|
||||
private SlidingTabLayout mSlidingTabLayout;
|
||||
private ViewPager mViewPager;
|
||||
private View view;
|
||||
private FirebaseAnalytics screenName;
|
||||
|
||||
/**
|
||||
* @param changeLog
|
||||
* @param flag
|
||||
*/
|
||||
public static void setChangeLog(ArrayList<Library> changeLog, int flag) {
|
||||
library = new ArrayList<>();
|
||||
library = changeLog;
|
||||
AboutActivity.flag = flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
screenName = FirebaseAnalytics.getInstance(getActivity());
|
||||
if (view != null) {
|
||||
ViewGroup parent = (ViewGroup) view.getParent();
|
||||
if (parent != null)
|
||||
parent.removeView(view);
|
||||
}
|
||||
try {
|
||||
view = inflater.inflate(R.layout.new_about_info_tab, container, false);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
ACRA.getErrorReporter().putCustomData("LAST_CLASS_ACCESSED", getClass().getSimpleName());
|
||||
query = new AQuery(getActivity());
|
||||
libs = new Libs(getActivity(), Libs.toStringArray(R.string.class.getFields()));
|
||||
String app_description = "";
|
||||
String app_name = "";
|
||||
Button btnUpdate = (Button) view.findViewById(R.id.btnCheckUpdate);
|
||||
|
||||
btnUpdate.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
cekVersion();
|
||||
}
|
||||
});
|
||||
//for LeadIn
|
||||
if (flag == 0) {
|
||||
app_description = libs.getInternLibraries().get(0).getLibraryDescription();
|
||||
app_name = libs.getInternLibraries().get(0).getLibraryName();
|
||||
} else if (flag == 1) {
|
||||
app_description = libs.getInternLibraries().get(1).getLibraryDescription();
|
||||
app_name = libs.getInternLibraries().get(1).getLibraryName();
|
||||
} else if (flag == 2) {
|
||||
app_description = libs.getInternLibraries().get(2).getLibraryDescription();
|
||||
app_name = libs.getInternLibraries().get(2).getLibraryName();
|
||||
}
|
||||
|
||||
query.id(R.id.appDesc).text(app_description);
|
||||
PackageInfo pInfo;
|
||||
try {
|
||||
pInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0);
|
||||
app_name = pInfo.versionName;
|
||||
Global.APP_VERSION = pInfo.versionName;
|
||||
Global.BUILD_VERSION = pInfo.versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
app_name = library.get(0).getLibraryName() + " v." + Global.APP_VERSION;
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
try {
|
||||
pInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0);
|
||||
app_name = pInfo.versionName;
|
||||
Global.APP_VERSION = pInfo.versionName;
|
||||
} catch (NameNotFoundException e1) {
|
||||
if (Global.IS_DEV)
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
query.id(R.id.lblApp).text(app_name);
|
||||
|
||||
AboutArrayAdapter adapter = new AboutArrayAdapter(getContext(), library);
|
||||
query.id(android.R.id.list).adapter(adapter);
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
UserHelp.showAllUserHelp(AboutActivity.this.getActivity(),AboutActivity.this.getClass().getSimpleName());
|
||||
}
|
||||
}, SHOW_USERHELP_DELAY_DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
//Set Firebase screen name
|
||||
screenName.setCurrentScreen(getActivity(), getString(R.string.screen_name_about), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if(item.getItemId() == R.id.mnGuide && !Global.BACKPRESS_RESTRICTION){
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
UserHelp.showAllUserHelp(getParentFragment().getActivity(), getParentFragment().getClass().getSimpleName());
|
||||
}
|
||||
}, SHOW_USERHELP_DELAY_DEFAULT);
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public void checkForUpdate(View view) {
|
||||
cekVersion();
|
||||
}
|
||||
|
||||
public void cekVersion() {
|
||||
new AsyncTask<Void, Void, JsonVersionResponse>() {
|
||||
String taskId = null;
|
||||
private ProgressDialog progressDialog;
|
||||
private String errMessage = null;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
progressDialog = ProgressDialog.show(getActivity(), "", getString(R.string.progressWait), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonVersionResponse doInBackground(Void... params) {
|
||||
JsonVersionResponse result = null;
|
||||
if (Tool.isInternetconnected(getActivity())) {
|
||||
MssRequestType request = new MssRequestType();
|
||||
request.setAudit(GlobalData.getSharedGlobalData().getAuditData());
|
||||
|
||||
String json = GsonHelper.toJson(request);
|
||||
String url = GlobalData.getSharedGlobalData().getURL_CHECK_UPDATE();
|
||||
boolean encrypt = GlobalData.getSharedGlobalData().isEncrypt();
|
||||
boolean decrypt = GlobalData.getSharedGlobalData().isDecrypt();
|
||||
HttpCryptedConnection httpConn = new HttpCryptedConnection(getActivity(), encrypt, decrypt);
|
||||
HttpConnectionResult serverResult = null;
|
||||
|
||||
//Firebase Performance Trace HTTP Request
|
||||
HttpMetric networkMetric =
|
||||
FirebasePerformance.getInstance().newHttpMetric(url, FirebasePerformance.HttpMethod.POST);
|
||||
Utility.metricStart(networkMetric, json);
|
||||
|
||||
try {
|
||||
serverResult = httpConn.requestToServer(url, json, Global.DEFAULTCONNECTIONTIMEOUT);
|
||||
Utility.metricStop(networkMetric, serverResult);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (Exception e1) {
|
||||
FireCrash.log(e1);
|
||||
}
|
||||
errMessage = e.getMessage();
|
||||
}
|
||||
|
||||
try {
|
||||
if(serverResult == null){
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
if (serverResult.isOK()) {
|
||||
String resultString = serverResult.getResult();
|
||||
JsonVersionResponse response = GsonHelper.fromJson(resultString, JsonVersionResponse.class);
|
||||
if (response.getStatus().getCode() == 0) {
|
||||
result = response;
|
||||
} else {
|
||||
errMessage = resultString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
} else {
|
||||
errMessage = getString(R.string.no_internet_connection);
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(JsonVersionResponse result) {
|
||||
if (progressDialog.isShowing()) {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
}
|
||||
if (errMessage != null && !errMessage.isEmpty()) {
|
||||
if(GlobalData.isRequireRelogin()){
|
||||
return;
|
||||
}
|
||||
Toast.makeText(getActivity(), errMessage, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
if (result != null && result.getListValues() != null) {
|
||||
boolean softUpdate = false;
|
||||
boolean forceUpdate = false;
|
||||
String listVersion = "";
|
||||
String otaLink = "";
|
||||
for (ListValue kv : result.getListValues()) {
|
||||
if (kv.getKey().equals(Global.GS_BUILD_NUMBER)) {
|
||||
listVersion = kv.getValue();
|
||||
} else if (kv.getKey().equals(Global.GS_URL_DOWNLOAD)) {
|
||||
otaLink = kv.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
int serverVersion = 0;
|
||||
try {
|
||||
serverVersion = Integer.valueOf(listVersion);
|
||||
} catch (NumberFormatException nfe) {
|
||||
FireCrash.log(nfe);
|
||||
}
|
||||
|
||||
String[] versions = Tool.split(listVersion, Global.DELIMETER_DATA);
|
||||
String thisVersion = Tool.split(Global.APP_VERSION, "-")[0];
|
||||
String lastVersionFromServer = null;
|
||||
for (int i = 0; i < versions.length; i++) {
|
||||
lastVersionFromServer = versions[i];
|
||||
if (thisVersion.equals(lastVersionFromServer)) {
|
||||
softUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!softUpdate) {
|
||||
forceUpdate = true;
|
||||
} else {
|
||||
if (thisVersion.equals(lastVersionFromServer))
|
||||
softUpdate = false;
|
||||
}
|
||||
|
||||
String uuidUser = GlobalData.getSharedGlobalData().getUser().getUuid_user();
|
||||
|
||||
Boolean loginEnabled = GeneralParameterDataAccess.getOne(getActivity(), uuidUser, Global.GS_VERS_LOGIN).getGs_value().equals("1");
|
||||
int versionLocal = 0;
|
||||
try {
|
||||
versionLocal = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0).versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (forceUpdate) {
|
||||
showAskForceUpdateDialog(otaLink);
|
||||
return;
|
||||
} else if (softUpdate) {
|
||||
showAskForUpdateDialog(otaLink);
|
||||
return;
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.msgNoNewVersion), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
if (serverVersion > versionLocal) {
|
||||
if (loginEnabled) {
|
||||
showAskForUpdateDialog(otaLink);
|
||||
} else {
|
||||
showAskForceUpdateDialog(otaLink);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.msgNoNewVersion), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private void showAskForceUpdateDialog(final String otaLink) {
|
||||
final NiftyDialogBuilder builder = NiftyDialogBuilder.getInstance(getActivity());
|
||||
builder.withTitle("Server")
|
||||
.withMessage(getString(R.string.critical_update))
|
||||
.withButton1Text(getString(R.string.update))
|
||||
.setButton1Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
openUpdate(otaLink);
|
||||
}
|
||||
});
|
||||
builder.isCancelable(false);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void showAskForUpdateDialog(final String otaLink) {
|
||||
final NiftyDialogBuilder builder = NiftyDialogBuilder.getInstance(getActivity());
|
||||
builder.withTitle("Server").isCancelableOnTouchOutside(false).isCancelable(false)
|
||||
.withMessage(getString(R.string.update_available))
|
||||
.withButton1Text(getString(R.string.later))
|
||||
.setButton1Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
builder.dismiss();
|
||||
}
|
||||
})
|
||||
.withButton2Text(getString(R.string.update))
|
||||
.setButton2Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
builder.dismiss();
|
||||
openUpdate(otaLink);
|
||||
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
private void openUpdate(String otaLink) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
File file = new File(getContext().getFilesDir(), "app.apk");
|
||||
if (file.exists()) {
|
||||
Uri apkURI = FileProvider.getUriForFile(
|
||||
getContext(), getContext().getPackageName() + ".provider", file);
|
||||
intent.setDataAndType(apkURI, "application/vnd.android.package-archive");
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
DownloadUpdate downloadUpdate = new DownloadUpdate(getContext());
|
||||
downloadUpdate.execute(otaLink);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package com.adins.mss.base.about.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.adins.mss.base.R;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.todolist.form.TaskList_Fragment;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.foundation.dialog.NiftyDialogBuilder;
|
||||
import com.github.jjobes.slidedatetimepicker.SlidingTabLayout;
|
||||
|
||||
//import static com.google.android.gms.internal.a.R;
|
||||
|
||||
/**
|
||||
* Created by gigin.ginanjar on 15/08/2016.
|
||||
*/
|
||||
public class AboutInfoTab extends Fragment {
|
||||
public static boolean isMenuClicked = false;
|
||||
private static Menu mainMenu;
|
||||
View view;
|
||||
private Context mContext;
|
||||
private ViewPager mViewPager;
|
||||
private ViewPagerAdapter mViewPagerAdapter;
|
||||
private SlidingTabLayout mSlidingTabLayout;
|
||||
private boolean isError = false;
|
||||
private String message;
|
||||
private Fragment activeFragment;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
mContext = activity;
|
||||
try {
|
||||
isError = getArguments().getBoolean(TaskList_Fragment.BUND_KEY_ISERROR, false);
|
||||
message = getArguments().getString(TaskList_Fragment.BUND_KEY_MESSAGE, "");
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
view = inflater.inflate(R.layout.about_info_tab, container, false);
|
||||
|
||||
//2017/09/07 | Nendi: add Title on toolbar
|
||||
getActivity().findViewById(com.adins.mss.base.R.id.search).setVisibility(View.GONE);
|
||||
getActivity().findViewById(R.id.spinner).setVisibility(View.GONE);
|
||||
getActivity().setTitle(getString(R.string.title_mn_about));
|
||||
|
||||
setupViews(view);
|
||||
initViewPager();
|
||||
initTabs();
|
||||
setHasOptionsMenu(true);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void initTabs() {
|
||||
// Set intial date on date tab
|
||||
updateAppTab();
|
||||
|
||||
// Set initial time on time tab
|
||||
updateDeviceTab();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
try {
|
||||
mainMenu.findItem(R.id.menuMore).setVisible(false);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
super.onDestroyView();
|
||||
Utility.freeMemory();
|
||||
}
|
||||
|
||||
private void updateAppTab() {
|
||||
mSlidingTabLayout.setTabText(1, getResources().getString(R.string.tabDevice));
|
||||
}
|
||||
|
||||
private void updateDeviceTab() {
|
||||
mSlidingTabLayout.setTabText(0, getResources().getString(R.string.tabApplication));
|
||||
}
|
||||
|
||||
private void initViewPager() {
|
||||
mViewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
|
||||
mViewPager.setAdapter(mViewPagerAdapter);
|
||||
|
||||
// Setting this custom layout for each tab ensures that the tabs will
|
||||
// fill all available horizontal space.
|
||||
|
||||
mSlidingTabLayout.setCustomTabView(R.layout.custom_tab_tasklist, R.id.tabTextTaskList);
|
||||
mSlidingTabLayout.setSelectedIndicatorColors(ContextCompat.getColor(getActivity(), R.color.tv_white),
|
||||
ContextCompat.getColor(getActivity(), R.color.tv_white));
|
||||
mSlidingTabLayout.setDividerColors(ContextCompat.getColor(getActivity(), R.color.tv_white),
|
||||
ContextCompat.getColor(getActivity(), R.color.tv_white));
|
||||
mSlidingTabLayout.setViewPager(mViewPager);
|
||||
if (isError) {
|
||||
isError = false;
|
||||
NiftyDialogBuilder dialogBuilder = NiftyDialogBuilder.getInstance(getActivity());
|
||||
|
||||
if (!dialogBuilder.isShowing()) {
|
||||
dialogBuilder.withTitle(getResources().getString(R.string.warning_capital)).
|
||||
withMessage(message).isCancelable(true).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupViews(View v) {
|
||||
mViewPager = (ViewPager) v.findViewById(R.id.pager);
|
||||
mSlidingTabLayout = (SlidingTabLayout) v.findViewById(R.id.slidingTabLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// isMenuClicked = false;
|
||||
// getActivity().getActionBar().setTitle(getString(R.string.title_mn_about));
|
||||
Utility.freeMemory();
|
||||
// MainMenuActivity.setDrawerPosition(getString(R.string.title_mn_about));
|
||||
// if(view!=null) {
|
||||
// initViewPager();
|
||||
// initTabs();
|
||||
// }
|
||||
getActivity().findViewById(com.adins.mss.base.R.id.search).setVisibility(View.GONE);
|
||||
getActivity().findViewById(R.id.spinner).setVisibility(View.GONE);
|
||||
getActivity().setTitle(getString(R.string.title_mn_about));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
}
|
||||
|
||||
private class ViewPagerAdapter extends FragmentPagerAdapter {
|
||||
public ViewPagerAdapter(FragmentManager fm) {
|
||||
super(fm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
Fragment fragment = null;
|
||||
switch (position) {
|
||||
case 0:
|
||||
fragment = new AboutActivity();
|
||||
break;
|
||||
case 1:
|
||||
fragment = new DeviceInfoFragment();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package com.adins.mss.base.about.activity;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.StatFs;
|
||||
import android.provider.Settings;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.adins.mss.base.R;
|
||||
import com.adins.mss.base.networkmonitor.NetworkMonitorDataUsage;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.foundation.formatter.Tool;
|
||||
import com.androidquery.AQuery;
|
||||
import com.github.jjobes.slidedatetimepicker.SlidingTabLayout;
|
||||
import com.mikepenz.aboutlibraries.Libs;
|
||||
import com.mikepenz.aboutlibraries.entity.Library;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
||||
import static com.pax.ippi.impl.NeptuneUser.getApplicationContext;
|
||||
|
||||
|
||||
/**
|
||||
* @author gigin.ginanjar
|
||||
*/
|
||||
public class DeviceInfoFragment extends Fragment {
|
||||
public static boolean backEnabled = true;
|
||||
private static ArrayList<Library> library;
|
||||
private static int flag;
|
||||
public Libs libs;
|
||||
AQuery query;
|
||||
int battery;
|
||||
long appSize;
|
||||
String txtMobileData;
|
||||
NetworkMonitorDataUsage monitorDU = new NetworkMonitorDataUsage();
|
||||
private SlidingTabLayout mSlidingTabLayout;
|
||||
private ViewPager mViewPager;
|
||||
|
||||
/**
|
||||
* @param changeLog
|
||||
* @param flag
|
||||
*/
|
||||
public static void setChangeLog(ArrayList<Library> changeLog, int flag) {
|
||||
library = new ArrayList<Library>();
|
||||
library = changeLog;
|
||||
DeviceInfoFragment.flag = flag;
|
||||
}
|
||||
|
||||
public static long getAvailableInternalMemorySize() {
|
||||
File path = Environment.getDataDirectory();
|
||||
StatFs stat = new StatFs(path.getPath());
|
||||
long blockSize = 0;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
blockSize = stat.getBlockSizeLong();
|
||||
} else {
|
||||
blockSize = stat.getBlockSize();
|
||||
}
|
||||
long availableBlocks = 0;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
availableBlocks = stat.getAvailableBlocksLong();
|
||||
} else {
|
||||
availableBlocks = stat.getAvailableBlocks();
|
||||
}
|
||||
return (availableBlocks * blockSize) / 1048576;
|
||||
}
|
||||
|
||||
public int getBatteryLevel() {
|
||||
//int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
|
||||
|
||||
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
Intent batteryStatus = getActivity().registerReceiver(null, ifilter);
|
||||
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
||||
// int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
|
||||
// int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
|
||||
int battery = (level * 100) / scale;
|
||||
// int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);\
|
||||
return battery;
|
||||
}
|
||||
|
||||
public long getAppSize() {
|
||||
try {
|
||||
appSize = new File(getActivity().getPackageManager().getApplicationInfo(getActivity().getPackageName(), 0).publicSourceDir).length();
|
||||
} catch (NameNotFoundException e) {
|
||||
ACRA.getErrorReporter().putCustomData("errorNameNotFound", e.getMessage());
|
||||
ACRA.getErrorReporter().putCustomData("errorNameNotFound", DateFormat.format("yyyy.MM.dd G \'at\' HH:mm:ss z", Calendar.getInstance().getTime()).toString());
|
||||
ACRA.getErrorReporter().handleSilentException(new Exception("Exception saat set getNameFile"));
|
||||
e.printStackTrace();
|
||||
}
|
||||
return appSize / 1048576;
|
||||
}
|
||||
|
||||
public String getMobileDataUsage() {
|
||||
String mobileData = Long.toString(monitorDU.getDataThisDay(getContext()) / 1024);
|
||||
int size = 0;
|
||||
for (int i = 0; i < mobileData.length(); i++) {
|
||||
size += 1;
|
||||
}
|
||||
if (size <= 3)
|
||||
txtMobileData = mobileData + " KB";
|
||||
else if (size > 3 && size <= 6)
|
||||
txtMobileData = mobileData.substring(0, mobileData.length() - 3) + " MB";
|
||||
else
|
||||
txtMobileData = mobileData.substring(0, mobileData.length() - 3) + " GB";
|
||||
return txtMobileData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
View view = inflater.inflate(R.layout.new_device_info_tab, container, false);
|
||||
TextView txtOsVer = (TextView) view.findViewById(R.id.txtOsVer);
|
||||
TextView txtAppVer = (TextView) view.findViewById((R.id.txtAppVer));
|
||||
TextView txtBattery = (TextView) view.findViewById((R.id.txtBattery));
|
||||
// TextView txtDataUsage = (TextView) view.findViewById((R.id.txtDataUsage));
|
||||
TextView txtMobileDataUsage = (TextView) view.findViewById((R.id.txtMobileDataUsage));
|
||||
TextView txtMemoryAvailable = (TextView) view.findViewById((R.id.txtMemoryAvailable));
|
||||
TextView txtAndroidID = (TextView) view.findViewById((R.id.txtAndroidId));
|
||||
|
||||
ACRA.getErrorReporter().putCustomData("LAST_CLASS_ACCESSED", getClass().getSimpleName());
|
||||
txtAppVer.setText(getString(R.string.appVer) + " : " + Global.APP_VERSION);
|
||||
txtOsVer.setText(getString(R.string.androidVersion) + " : " + Build.VERSION.RELEASE);
|
||||
txtBattery.setText(getString(R.string.batteryPercen) + " : " + getBatteryLevel() + " %");
|
||||
// olivia : UPDATE - Application Storage dihilangkan
|
||||
// txtDataUsage.setText(getString(R.string.appStorage) + " : " + Tool.separateThousand((double) getAppSize())+ " MB");
|
||||
txtMobileDataUsage.setText(getString(R.string.dataUsage) + " : " + getMobileDataUsage());
|
||||
txtMemoryAvailable.setText(getString(R.string.deviceStorage) + " : " + Tool.separateThousand(getAvailableInternalMemorySize()) + " MB");
|
||||
|
||||
final String android_id;
|
||||
if(Build.VERSION.SDK_INT > 28){
|
||||
android_id = Settings.Secure.getString(getContext().getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||
txtAndroidID.setVisibility(View.VISIBLE);
|
||||
}else {
|
||||
android_id = "";
|
||||
txtAndroidID.setVisibility(View.GONE);
|
||||
}
|
||||
txtAndroidID.setText(getString(R.string.androidID)+" : "+android_id);
|
||||
txtAndroidID.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("Clip", android_id);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(getContext(),getString(R.string.copied),Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.adins.mss.base.about.activity;
|
||||
|
||||
import com.adins.mss.foundation.http.MssResponseType;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JsonVersionResponse extends MssResponseType {
|
||||
|
||||
@SerializedName("listValue")
|
||||
List<ListValue> listValue;
|
||||
|
||||
public List<ListValue> getListValues() {
|
||||
return this.listValue;
|
||||
}
|
||||
|
||||
public void setListValues(List<ListValue> listValue) {
|
||||
this.listValue = listValue;
|
||||
}
|
||||
|
||||
public class ListValue {
|
||||
@SerializedName("key")
|
||||
String key;
|
||||
@SerializedName("value")
|
||||
String value;
|
||||
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package com.adins.mss.base.api;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.adins.mss.base.GlobalData;
|
||||
import com.adins.mss.base.R;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.models.ChangePasswordRequestModel;
|
||||
import com.adins.mss.base.models.ChangePasswordResponseModel;
|
||||
import com.adins.mss.base.util.GsonHelper;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.foundation.formatter.Tool;
|
||||
import com.adins.mss.foundation.http.HttpConnectionResult;
|
||||
import com.adins.mss.foundation.http.HttpCryptedConnection;
|
||||
import com.adins.mss.foundation.http.net.HttpClient;
|
||||
import com.google.firebase.perf.FirebasePerformance;
|
||||
import com.google.firebase.perf.metrics.HttpMetric;
|
||||
|
||||
/**
|
||||
* Created by adityapurwa on 30/03/15.
|
||||
*/
|
||||
public class ChangePasswordApi {
|
||||
private final Context context;
|
||||
private final Activity activity;
|
||||
private final HttpClient http;
|
||||
private ChangePasswordApiCallback callback;
|
||||
|
||||
public ChangePasswordApi(Activity context) {
|
||||
this.activity = context;
|
||||
this.context = context;
|
||||
this.http = new HttpClient(context);
|
||||
}
|
||||
|
||||
public ChangePasswordApiCallback getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public void setCallback(ChangePasswordApiCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void execute(final ChangePasswordRequestModel request) {
|
||||
|
||||
new AsyncTask<Void, Void, ChangePasswordResponseModel>() {
|
||||
private ProgressDialog progressDialog;
|
||||
private String errMessage;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
progressDialog = ProgressDialog.show(context, "", context.getString(R.string.contact_server), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChangePasswordResponseModel doInBackground(Void... params) {
|
||||
try {
|
||||
if (Tool.isInternetconnected(context)) {
|
||||
String json = GsonHelper.toJson(request);
|
||||
boolean encrypt = GlobalData.getSharedGlobalData().isEncrypt();
|
||||
boolean decrypt = GlobalData.getSharedGlobalData().isDecrypt();
|
||||
HttpCryptedConnection httpConn = new HttpCryptedConnection(activity, encrypt, decrypt);
|
||||
HttpConnectionResult serverResult = null;
|
||||
String url = GlobalData.getSharedGlobalData().getURL_CHANGEPASSWORD();
|
||||
|
||||
//Firebase Performance Trace HTTP Request
|
||||
HttpMetric networkMetric =
|
||||
FirebasePerformance.getInstance().newHttpMetric(url, FirebasePerformance.HttpMethod.POST);
|
||||
Utility.metricStart(networkMetric, json);
|
||||
|
||||
try {
|
||||
serverResult = httpConn.requestToServer(url, json, Global.DEFAULTCONNECTIONTIMEOUT);
|
||||
Utility.metricStop(networkMetric, serverResult);
|
||||
} catch (Exception e) {
|
||||
errMessage = e.getMessage();
|
||||
FireCrash.log(e);
|
||||
}
|
||||
String body = null;
|
||||
if (serverResult != null && serverResult.isOK()) {
|
||||
body = serverResult.getResult();
|
||||
ChangePasswordResponseModel result = null;
|
||||
try {
|
||||
result = GsonHelper.fromJson(body, ChangePasswordResponseModel.class);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
errMessage = e.getMessage();
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if(serverResult != null && serverResult.getResult() != null)
|
||||
errMessage = serverResult.getResult();
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
errMessage = context.getString(R.string.no_internet_connection);
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(ChangePasswordResponseModel result) {
|
||||
super.onPostExecute(result);
|
||||
if (progressDialog.isShowing()) {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
if (errMessage != null && getCallback() != null){
|
||||
getCallback().onFailed(errMessage);
|
||||
}else{
|
||||
getCallback().onFailed(context.getString(R.string.error_unknown));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result.getStatus().getCode() == 0) {
|
||||
if (getCallback() != null) getCallback().onSuccess();
|
||||
} else {
|
||||
if (getCallback() != null) {
|
||||
if (result.getStatus().getMessage() != null)
|
||||
getCallback().onFailed(result.getStatus().getMessage());
|
||||
else
|
||||
getCallback().onFailed(String.valueOf(result.getStatus().getCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.adins.mss.base.api;
|
||||
|
||||
/**
|
||||
* Created by adityapurwa on 30/03/15.
|
||||
*/
|
||||
public interface ChangePasswordApiCallback {
|
||||
void onFailed(String message);
|
||||
|
||||
void onSuccess();
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.adins.mss.base.api;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.adins.mss.base.GlobalData;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.models.CheckResubmitRequest;
|
||||
import com.adins.mss.base.util.GsonHelper;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.foundation.http.HttpConnectionResult;
|
||||
import com.adins.mss.foundation.http.HttpCryptedConnection;
|
||||
import com.adins.mss.foundation.http.MssResponseType;
|
||||
import com.google.firebase.perf.FirebasePerformance;
|
||||
import com.google.firebase.perf.metrics.HttpMetric;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by eric.sn on 4/5/2017.
|
||||
*/
|
||||
|
||||
public class CheckResubmitApi {
|
||||
private final Context context;
|
||||
|
||||
public CheckResubmitApi(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public MssResponseType request(String uuidtaskH) throws IOException {
|
||||
CheckResubmitRequest request = new CheckResubmitRequest();
|
||||
request.setUuidTaskH(uuidtaskH);
|
||||
request.setAudit(GlobalData.getSharedGlobalData().getAuditData());
|
||||
|
||||
String requestJson = GsonHelper.toJson(request);
|
||||
|
||||
String url = GlobalData.getSharedGlobalData().getURL_CHECK_RESUBMIT();
|
||||
boolean encrypt = GlobalData.getSharedGlobalData().isEncrypt();
|
||||
boolean decrypt = GlobalData.getSharedGlobalData().isDecrypt();
|
||||
HttpCryptedConnection httpConn = new HttpCryptedConnection(context, encrypt, decrypt);
|
||||
HttpConnectionResult serverResult = null;
|
||||
|
||||
HttpMetric networkMetric =
|
||||
FirebasePerformance.getInstance().newHttpMetric(url, FirebasePerformance.HttpMethod.POST);
|
||||
Utility.metricStart(networkMetric, requestJson);
|
||||
|
||||
try {
|
||||
serverResult = httpConn.requestToServer(url, requestJson, Global.DEFAULTCONNECTIONTIMEOUT);
|
||||
Utility.metricStop(networkMetric, serverResult);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
String responseJson = "";
|
||||
if (serverResult != null && serverResult.isOK()) {
|
||||
try {
|
||||
responseJson = serverResult.getResult();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
// bong 21 mei 15 - add or replace to local database
|
||||
MssResponseType checkResubmitResp = GsonHelper.fromJson(responseJson, MssResponseType.class);
|
||||
return checkResubmitResp;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,772 @@
|
|||
package com.adins.mss.base.authentication;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.adins.mss.base.AppContext;
|
||||
import com.adins.mss.base.GlobalData;
|
||||
import com.adins.mss.base.NewMainActivity;
|
||||
import com.adins.mss.base.R;
|
||||
import com.adins.mss.base.crashlytics.FireCrash;
|
||||
import com.adins.mss.base.dynamictheme.DynamicTheme;
|
||||
import com.adins.mss.base.dynamictheme.ThemeLoader;
|
||||
import com.adins.mss.base.timeline.TimelineManager;
|
||||
import com.adins.mss.base.util.GenericAsyncTask;
|
||||
import com.adins.mss.base.util.GenericAsyncTask.GenericTaskInterface;
|
||||
import com.adins.mss.base.util.GsonHelper;
|
||||
import com.adins.mss.base.util.LocaleHelper;
|
||||
import com.adins.mss.base.util.UserSession;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.dao.GeneralParameter;
|
||||
import com.adins.mss.dao.Menu;
|
||||
import com.adins.mss.dao.Timeline;
|
||||
import com.adins.mss.dao.User;
|
||||
import com.adins.mss.foundation.UserHelp.UserHelp;
|
||||
import com.adins.mss.foundation.db.dataaccess.GeneralParameterDataAccess;
|
||||
import com.adins.mss.foundation.db.dataaccess.MenuDataAccess;
|
||||
import com.adins.mss.foundation.db.dataaccess.TimelineDataAccess;
|
||||
import com.adins.mss.foundation.db.dataaccess.UserDataAccess;
|
||||
import com.adins.mss.foundation.formatter.Formatter;
|
||||
import com.adins.mss.foundation.formatter.Tool;
|
||||
import com.adins.mss.foundation.http.AuditDataType;
|
||||
import com.adins.mss.foundation.http.AuditDataTypeGenerator;
|
||||
import com.adins.mss.foundation.http.HttpConnectionResult;
|
||||
import com.adins.mss.foundation.http.HttpCryptedConnection;
|
||||
import com.adins.mss.foundation.http.MssRequestType;
|
||||
import com.adins.mss.foundation.http.MssResponseType;
|
||||
import com.adins.mss.foundation.http.MssResponseType.Status;
|
||||
import com.adins.mss.foundation.security.storepreferences.ObscuredSharedPreferences;
|
||||
import com.google.firebase.perf.FirebasePerformance;
|
||||
import com.google.firebase.perf.metrics.HttpMetric;
|
||||
|
||||
import org.acra.ACRA;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p> Used to authenticate user, using HttpCryptedConnection to send user credential to server, and receive server response
|
||||
*
|
||||
* @author glen.iglesias
|
||||
*/
|
||||
public class Authentication implements GenericTaskInterface {
|
||||
|
||||
public static final String LOGIN_PREFERENCES = "login_preferences";
|
||||
public static final String LOGIN_PREFERENCES_APPLICATION_CLEANSING = "login_preferences.APPLICATION_CLEANSING";
|
||||
public static final String SHARED_PREF = "sharedPreferencesAuthentication";
|
||||
public static final String SHARED_PREF_KEY_FRESH_INSTALL = "sharedPreferencesKey_freshInstall";
|
||||
public static final String SHARED_PREF_KEY_DB_SAVED = "sharedPreferencesKey_dbsaved";
|
||||
private static final int LOGIN_SUCCESS = 1;
|
||||
private static final int FORCE_UPDATE = 2;
|
||||
private static final int FORCE_CLEANSING = 3;
|
||||
private static final int LOGIN_FAIL = 0;
|
||||
private static final String TASK_OBJ_KEY_CONN = "task_object_key_connection";
|
||||
private static final String TASK_OBJ_KEY_URL = "task_object_key_url";
|
||||
private static final String TASK_OBJ_KEY_JSON = "task_object_key_json";
|
||||
private static final String TASK_OBJ_KEY_DELEGATE = "task_object_key_delegate";
|
||||
private static final String TASK_OBJ_KEY_CONTEXT = "task_object_key_context";
|
||||
private static final String TASK_OBJ_KEY_RESULT = "task_object_key_result";
|
||||
private static final String TASK_OBJ_KEY_BUILD_NUMBER = "task_object_key_build_number";
|
||||
private static final String TASK_OBJ_KEY_LOGIN_ID = "task_object_key_login_id";
|
||||
//Debug
|
||||
public static boolean enableSimulatedResult = false;
|
||||
public static int simulatedResult = 1;
|
||||
protected static String temp_loginID;
|
||||
protected static String temp_password;
|
||||
private String url;
|
||||
private AuthenticationHandler handler;
|
||||
private boolean encrypt;
|
||||
private boolean decrypt;
|
||||
|
||||
/**
|
||||
* Default constructor. Will fetch data from GlobalData if any
|
||||
*/
|
||||
public Authentication() {
|
||||
GlobalData globData = GlobalData.getSharedGlobalData();
|
||||
url = globData.getURL_LOGIN();
|
||||
encrypt = globData.isEncrypt();
|
||||
decrypt = globData.isDecrypt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send user credential over HTTP to server. Will replace stored AuditDataType in GlobalData with newly
|
||||
* generated one. Will also store successfully logged in user data in GlobalData
|
||||
* <br>Connection will run on async task
|
||||
*
|
||||
* @param context
|
||||
* @param url target URL
|
||||
* @param username username to be authenticated
|
||||
* @param password password to be authenticated
|
||||
* @param encrypt flag to encrypt sent data to server
|
||||
* @param decrypt flag to decrypt server response message
|
||||
*/
|
||||
public static void authenticateOnBackground(Context context, String url, String username, String password, boolean encrypt, boolean decrypt, int buildNumber, AuthenticationHandler handler) {
|
||||
|
||||
Map<String, String> listImei = AuditDataTypeGenerator.getListImeiFromDevice(context);
|
||||
GlobalData.getSharedGlobalData().setImei(listImei.get(MssRequestType.UN_KEY_IMEI));
|
||||
if (listImei.get(MssRequestType.UN_KEY_IMEI2) != null) {
|
||||
GlobalData.getSharedGlobalData().setImei2(listImei.get(MssRequestType.UN_KEY_IMEI2));
|
||||
}
|
||||
|
||||
//generate and store new AuditDataType
|
||||
String language = LocaleHelper.getLanguage(context);
|
||||
LocaleHelper.setLocale(context,language);
|
||||
GlobalData.getSharedGlobalData().setLocale(language);
|
||||
|
||||
AuditDataType auditDataType = AuditDataTypeGenerator.generateAuditDataType(username);
|
||||
storeAuditData(auditDataType);
|
||||
|
||||
//freshInstall
|
||||
boolean needUpdateVersion = UserSession.needUpdateVersion();
|
||||
boolean isFresh = isFreshInstall(context);
|
||||
boolean isFreshInstall = needUpdateVersion || isFresh;
|
||||
|
||||
HttpCryptedConnection httpConn = new HttpCryptedConnection(context, encrypt, decrypt);
|
||||
|
||||
temp_loginID = username;
|
||||
temp_password = password;
|
||||
String json = getStringForSending(username, password, isFreshInstall);
|
||||
if (Global.IS_DEV)
|
||||
System.out.println(json);
|
||||
|
||||
//use asynctask instead
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put(TASK_OBJ_KEY_CONN, httpConn);
|
||||
params.put(TASK_OBJ_KEY_URL, url);
|
||||
params.put(TASK_OBJ_KEY_JSON, json);
|
||||
params.put(TASK_OBJ_KEY_DELEGATE, handler);
|
||||
params.put(TASK_OBJ_KEY_CONTEXT, context);
|
||||
params.put(TASK_OBJ_KEY_BUILD_NUMBER, buildNumber);
|
||||
params.put(TASK_OBJ_KEY_LOGIN_ID, username);
|
||||
|
||||
GenericAsyncTask task = new GenericAsyncTask(new Authentication());
|
||||
task.setAdditionalObject(params);
|
||||
task.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send user credential over HTTP to server using GlobalData settings, like url, encryption, and decryption
|
||||
* <br>Connection will run on async task
|
||||
*
|
||||
* @param username username to be authenticated
|
||||
* @param password password to be authenticated
|
||||
*/
|
||||
public static void authenticateOnBackground(Context context, String username, String password, int buildNumber, AuthenticationHandler handler) {
|
||||
GlobalData globData = GlobalData.getSharedGlobalData();
|
||||
|
||||
String url = globData.getURL_LOGIN();
|
||||
boolean enc = globData.isEncrypt();
|
||||
boolean dec = globData.isDecrypt();
|
||||
|
||||
authenticateOnBackground(context, url, username, password, enc, dec, buildNumber, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a way to interpret server response and translate into AuthenticationResultBean
|
||||
* <p>Should you choose a different way, override this method
|
||||
*
|
||||
* @param result a string received from server
|
||||
* @return an AuthenticationResultBean as standard result
|
||||
*/
|
||||
protected static AuthenticationResultBean mapResultToBean(String result, String login_id_tenant) {
|
||||
//Default, treat result as JSON with format of LoginUserResponse
|
||||
LoginUserResponse responseBean;
|
||||
try {
|
||||
responseBean = GsonHelper.fromJson(result, LoginUserResponse.class);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
Status resultStatus = responseBean.getStatus();
|
||||
|
||||
List<GeneralParameter> generalParameterss = responseBean.getListGeneralParameter();
|
||||
|
||||
//add tenant id to general parameters
|
||||
GeneralParameter gP = new GeneralParameter();
|
||||
if (!generalParameterss.isEmpty()) {
|
||||
gP.setUuid_general_parameter(Tool.getUUID());
|
||||
gP.setGs_code(Global.GS_TENANT_ID);
|
||||
gP.setGs_value(login_id_tenant);
|
||||
generalParameterss.add(0, gP);
|
||||
}
|
||||
|
||||
|
||||
//20 Jan 2015, adapt to backend system
|
||||
AuthenticationResultBean resultBean = new AuthenticationResultBean();
|
||||
|
||||
if (resultStatus.getCode() == 0) { //success login
|
||||
User user = responseBean.getUser();
|
||||
|
||||
resultBean.setActiveUser(true);
|
||||
String loginGenParam = getGeneralParameter(Global.GS_VERS_LOGIN, generalParameterss);
|
||||
if(loginGenParam != null && loginGenParam.equals("1")){
|
||||
resultBean.setForceUpdate(true);
|
||||
}
|
||||
resultBean.setGeneralParameters(responseBean.getListGeneralParameter());
|
||||
resultBean.setListMenu(responseBean.getListMenu());
|
||||
resultBean.setLastUpdateVersion(getGeneralParameter(Global.GS_BUILD_NUMBER, generalParameterss));
|
||||
resultBean.setLoginResult(LOGIN_SUCCESS);
|
||||
resultBean.setNeedUpdatePassword(user.getChg_pwd().equals(Global.TRUE_STRING));
|
||||
resultBean.setOtaLink(getGeneralParameter(Global.GS_URL_DOWNLOAD, generalParameterss));
|
||||
resultBean.setUserInfo(user);
|
||||
} else { //login failed
|
||||
resultBean.setLoginResult(LOGIN_FAIL);
|
||||
resultBean.setMessage(resultStatus.getMessage());
|
||||
}
|
||||
return resultBean;
|
||||
}
|
||||
|
||||
private static String getGeneralParameter(String name, List<GeneralParameter> generalParameterss) {
|
||||
for (GeneralParameter param : generalParameterss) {
|
||||
if (param.getGs_code().equals(name)) {
|
||||
return param.getGs_value();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to implement different method of storing AuditData
|
||||
*
|
||||
* @param auditData
|
||||
*/
|
||||
protected static void storeAuditData(AuditDataType auditData) {
|
||||
GlobalData.getSharedGlobalData().setAuditData(auditData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to provide other format of String to send to server
|
||||
* <p>Default is using AuthenticationModel as the format
|
||||
*
|
||||
* @param username username the user input
|
||||
* @param password password the user input
|
||||
* @param isFreshInstall true if this application never had any user login yet
|
||||
* @return string of data (JSON or not) to send to server
|
||||
* @see MssRequestType
|
||||
*/
|
||||
protected static String getStringForSending(String username, String password, boolean isFreshInstall) {
|
||||
//Initiate audit data
|
||||
AuditDataType audit = AuditDataTypeGenerator.generateActiveUserAuditData();
|
||||
GlobalData.getSharedGlobalData().setAuditData(audit);
|
||||
|
||||
String strFlagFreshInstall = isFreshInstall ? "1" : "0";
|
||||
|
||||
//Create LoginUserRequest
|
||||
LoginUserRequest data = new LoginUserRequest();
|
||||
data.setAudit(audit);
|
||||
data.setUsername(username);
|
||||
data.setPassword(password);
|
||||
data.setFlagFreshInstall(strFlagFreshInstall);
|
||||
data.setFcmTokenId(Global.Token);
|
||||
|
||||
//GlobalData.imei were set from method authenticate
|
||||
data.addImeiAndroidIdToUnstructured();
|
||||
|
||||
String json = Formatter.getJsonFromObject(data);
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set as no longer a fresh install to application preferences. On next call to authenticate(), method would give
|
||||
* false to isFreshInstall
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public static void setAsNonFreshInstall(Context context) {
|
||||
ObscuredSharedPreferences pref = ObscuredSharedPreferences.getPrefs(context, SHARED_PREF, Context.MODE_PRIVATE);
|
||||
pref.edit().putString(SHARED_PREF_KEY_FRESH_INSTALL, "false").apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set as a fresh install to application preferences. On next call to authenticate(), method would give
|
||||
* true to isFreshInstall
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public static void setAsFreshInstall(Context context) {
|
||||
ObscuredSharedPreferences pref = ObscuredSharedPreferences.getPrefs(context, SHARED_PREF, Context.MODE_PRIVATE);
|
||||
pref.edit().putString(SHARED_PREF_KEY_FRESH_INSTALL, "true").apply();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to check if application is first-time running after installation and has device's IMEI not registered yet
|
||||
* based on whether the sharedPreference exist or not.
|
||||
* <p/>
|
||||
* Override this method to implement other method of determining if it's a fresh install
|
||||
*
|
||||
* @param context
|
||||
* @return true if it is a fresh install application, false if it is not
|
||||
*/
|
||||
public static boolean isFreshInstall(Context context) {
|
||||
ObscuredSharedPreferences pref = ObscuredSharedPreferences.getPrefs(context, SHARED_PREF, Context.MODE_PRIVATE);
|
||||
String isFreshInstall = pref.getString(SHARED_PREF_KEY_FRESH_INSTALL, "true"); //if no preference exist, meaning it's a new install
|
||||
return Boolean.parseBoolean(isFreshInstall);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method and pass parameters object to save it to database
|
||||
* <p/>
|
||||
* <p>Override this method to change how application save the parameters
|
||||
*/
|
||||
protected static void saveServerParameters(Context context, List<GeneralParameter> generalParameters) {
|
||||
|
||||
|
||||
for (GeneralParameter gp : generalParameters) {
|
||||
String temp_uuid_user = gp.getUuid_user();
|
||||
User user = UserDataAccess.getOne(context, temp_uuid_user);
|
||||
gp.setUser(user);
|
||||
GeneralParameterDataAccess.addOrReplace(context, gp);
|
||||
}
|
||||
|
||||
//save to GlobalData
|
||||
GlobalData.getSharedGlobalData().loadGeneralParameters(generalParameters);
|
||||
}
|
||||
|
||||
protected static void saveUserInfo(Context context, User authenticatedUser) {
|
||||
String temp_uuid_user = authenticatedUser.getUuid_user();
|
||||
User user = UserDataAccess.getOne(context, temp_uuid_user);
|
||||
if (user != null) {
|
||||
user.setLogin_id(temp_loginID);
|
||||
user.setPassword(temp_password);
|
||||
if (Global.IS_LOGIN) {
|
||||
user.setBranch_name(authenticatedUser.getBranch_name());
|
||||
Global.IS_LOGIN = false;
|
||||
}
|
||||
|
||||
//olivia : update jam start dan end tracking
|
||||
user.setIs_tracking(authenticatedUser.getIs_tracking());
|
||||
if (authenticatedUser.getIs_tracking() != null && authenticatedUser.getIs_tracking().equals("1")) {
|
||||
user.setStart_time(authenticatedUser.getStart_time());
|
||||
user.setEnd_time(authenticatedUser.getEnd_time());
|
||||
}
|
||||
if(authenticatedUser.getTracking_days() != null && !authenticatedUser.getTracking_days().equals("")){
|
||||
user.setTracking_days(authenticatedUser.getTracking_days());
|
||||
}
|
||||
|
||||
user.setCash_on_hand(authenticatedUser.getCash_on_hand());
|
||||
user.setCash_limit(authenticatedUser.getCash_limit());
|
||||
|
||||
UserDataAccess.addOrReplace(context, user);
|
||||
// save to GlobalData
|
||||
GlobalData.getSharedGlobalData().setUser(user);
|
||||
Global.user = user;
|
||||
} else {
|
||||
authenticatedUser.setLogin_id(temp_loginID);
|
||||
authenticatedUser.setPassword(temp_password);
|
||||
UserDataAccess.addOrReplace(context, authenticatedUser);
|
||||
// save to GlobalData
|
||||
GlobalData.getSharedGlobalData().setUser(authenticatedUser);
|
||||
Global.user = authenticatedUser;
|
||||
}
|
||||
}
|
||||
|
||||
protected static void saveMenu(Context context, List<Menu> listMenu) {
|
||||
for (Menu menu : listMenu) {
|
||||
String temp_uuid_user = menu.getUuid_user();
|
||||
User user = UserDataAccess.getOne(context, temp_uuid_user);
|
||||
menu.setUser(user);
|
||||
MenuDataAccess.addOrReplace(context, menu);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void updateTimeline(Context context) {
|
||||
// 2017/10/09 | olivia : hapus timeline yang sudah lebih dari range di general parameter
|
||||
int range = GlobalData.getSharedGlobalData().getKeepTimelineInDays();
|
||||
List<Timeline> timelines = TimelineManager.getAllTimeline(context);
|
||||
for (Timeline timeline : timelines) {
|
||||
if (timeline.getDtm_crt().before(Tool.getIncrementDate(-range)))
|
||||
TimelineDataAccess.delete(context, timeline);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send user credential over HTTP to server
|
||||
* <br>Will run connection on background thread
|
||||
*
|
||||
* @param context
|
||||
* @param username
|
||||
* @param password
|
||||
*/
|
||||
public void authenticateOnBackground(Context context, String username, String password, int buildNumber) {
|
||||
authenticateOnBackground(context, url, username, password, encrypt, decrypt, buildNumber, handler);
|
||||
}
|
||||
|
||||
//=== Generic Task Interface Callbacks ===//
|
||||
|
||||
@Override
|
||||
public void onPreExecute(GenericAsyncTask task) {
|
||||
Log.d("Log","OnPreExecute");//must override this
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doInBackground(GenericAsyncTask task, String... args) {
|
||||
|
||||
HttpCryptedConnection httpConn = (HttpCryptedConnection) task.getAdditionalObject().get(TASK_OBJ_KEY_CONN);
|
||||
String json = (String) task.getAdditionalObject().get(TASK_OBJ_KEY_JSON);
|
||||
String url = (String) task.getAdditionalObject().get(TASK_OBJ_KEY_URL);
|
||||
HttpConnectionResult result = null;
|
||||
|
||||
//Firebase Performance Trace HTTP Request
|
||||
HttpMetric networkMetric =
|
||||
FirebasePerformance.getInstance().newHttpMetric(url, FirebasePerformance.HttpMethod.POST);
|
||||
Utility.metricStart(networkMetric, json);
|
||||
|
||||
try {
|
||||
result = httpConn.requestToServer(url, json, Global.DEFAULTCONNECTIONTIMEOUT);
|
||||
Utility.metricStop(networkMetric, result);
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (result != null) task.getAdditionalObject().put(TASK_OBJ_KEY_RESULT, result);
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute(GenericAsyncTask task, String result,
|
||||
String errMsg) {
|
||||
|
||||
HttpConnectionResult connResult = (HttpConnectionResult) task.getAdditionalObject().get(TASK_OBJ_KEY_RESULT);
|
||||
AuthenticationHandler handler = (AuthenticationHandler) task.getAdditionalObject().get(TASK_OBJ_KEY_DELEGATE);
|
||||
Context context = (Context) task.getAdditionalObject().get(TASK_OBJ_KEY_CONTEXT);
|
||||
String loginId = (String) task.getAdditionalObject().get(TASK_OBJ_KEY_LOGIN_ID);
|
||||
|
||||
if (handler != null) {
|
||||
if (connResult != null && connResult.isOK()) {
|
||||
//success
|
||||
|
||||
//convert to bean
|
||||
AuthenticationResultBean authResultBean = mapResultToBean(connResult.getResult(), loginId);
|
||||
|
||||
//bong 30 mar 15 - penjagaan jika belum log in di router tapi sudah dapat ip
|
||||
try {
|
||||
if (authResultBean == null) {
|
||||
String error = context.getString(R.string.request_error) + ".\n" + context.getString(R.string.connection_failed_wifi);
|
||||
connResult.setResult(error);
|
||||
handler.onConnectionFail(null, connResult);
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
handler.onConnectionFail(null, connResult);
|
||||
return;
|
||||
}
|
||||
|
||||
MssResponseType responseFromServer = GsonHelper.fromJson(connResult.getResult(), MssResponseType.class);
|
||||
|
||||
if (responseFromServer.getStatus().getCode() == Global.STATUS_CODE_APPL_CLEANSING) {
|
||||
NewMainActivity.Force_Uninstall = true;
|
||||
handler.onInactiveUser(null);
|
||||
|
||||
ObscuredSharedPreferences.Editor editor = ObscuredSharedPreferences.getPrefs(context, LOGIN_PREFERENCES, Context.MODE_PRIVATE).edit();
|
||||
editor.putString(LOGIN_PREFERENCES_APPLICATION_CLEANSING, "uninstall");
|
||||
editor.apply();
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
ObscuredSharedPreferences.Editor editor = ObscuredSharedPreferences.getPrefs(context, LOGIN_PREFERENCES, Context.MODE_PRIVATE).edit();
|
||||
editor.remove(LOGIN_PREFERENCES_APPLICATION_CLEANSING);
|
||||
editor.apply();
|
||||
} catch (Exception e) {
|
||||
FireCrash.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String message = authResultBean.getMessage();
|
||||
String otaLink = authResultBean.getOtaLink();
|
||||
|
||||
//get login status
|
||||
int status = 0;
|
||||
status = authResultBean.getLoginResult();
|
||||
|
||||
//debug
|
||||
if (enableSimulatedResult) {
|
||||
status = simulatedResult;
|
||||
}
|
||||
|
||||
if (status != LOGIN_FAIL) { //Login authorized
|
||||
boolean needUpdatePassword = authResultBean.needUpdatePassword();
|
||||
boolean pwdExp = "1".equals(authResultBean.getUserInfo().getPwd_exp());
|
||||
boolean forceUpdate = authResultBean.isForceUpdate();
|
||||
boolean isActiveUser = authResultBean.isActiveUser();
|
||||
List<GeneralParameter> generalParameters = authResultBean.getGeneralParameters();
|
||||
List<Menu> listMenu = authResultBean.getListMenu();
|
||||
User authenticatedUser = authResultBean.getUserInfo();
|
||||
|
||||
// bong - 30 jan 15 need set uuid_user to general parameter
|
||||
for (GeneralParameter generalParameter : generalParameters) {
|
||||
if (generalParameter.getUuid_user() == null || "".equals(generalParameter.getUuid_user()))
|
||||
generalParameter.setUuid_user(authResultBean.getUserInfo().getUuid_user());
|
||||
}
|
||||
|
||||
for (Menu menu : listMenu) {
|
||||
if (menu.getUuid_user() == null || "".equals(menu.getUuid_user()))
|
||||
menu.setUuid_user(authResultBean.getUserInfo().getUuid_user());
|
||||
}
|
||||
|
||||
boolean softUpdate = false;
|
||||
|
||||
String listVersion = authResultBean.getLastUpdateVersion();
|
||||
String[] versions = Tool.split(listVersion, Global.DELIMETER_DATA);
|
||||
String thisVersion = Tool.split(Global.APP_VERSION, "-")[0];
|
||||
String lastVersionFromServer = null;
|
||||
for (int i = 0; i < versions.length; i++) {
|
||||
lastVersionFromServer = versions[i];
|
||||
if (thisVersion.equals(lastVersionFromServer)) {
|
||||
softUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!softUpdate) {
|
||||
forceUpdate = true;
|
||||
} else {
|
||||
if (thisVersion.equals(lastVersionFromServer))
|
||||
softUpdate = false;
|
||||
}
|
||||
|
||||
GeneralParameterDataAccess.clean(context);
|
||||
MenuDataAccess.clean(context);
|
||||
|
||||
saveUserInfo(context, authenticatedUser);
|
||||
saveServerParameters(context, generalParameters);
|
||||
saveMenu(context, listMenu);
|
||||
|
||||
updateTimeline(context);
|
||||
|
||||
//GIGIN ~ SAVE USER INFO TO ACRA
|
||||
ACRA.getErrorReporter().putCustomData("UUID_USER", GlobalData.getSharedGlobalData().getUser().getUuid_user());
|
||||
ACRA.getErrorReporter().putCustomData("LOGIN_ID", GlobalData.getSharedGlobalData().getUser().getLogin_id());
|
||||
ACRA.getErrorReporter().putCustomData("JOB_DESCRIPTION", GlobalData.getSharedGlobalData().getUser().getJob_description());
|
||||
ACRA.getErrorReporter().putCustomData("BRANCH_NAME", GlobalData.getSharedGlobalData().getUser().getBranch_name());
|
||||
ACRA.getErrorReporter().putCustomData("TENANT_ID", GlobalData.getSharedGlobalData().getTenant());
|
||||
|
||||
// bong 11 march 15 - stored callerId in audit
|
||||
GlobalData.getSharedGlobalData().getAuditData().setCallerId(authResultBean.getUserInfo().getUuid_user());
|
||||
if (!isActiveUser) {
|
||||
status = FORCE_CLEANSING;
|
||||
} else if (forceUpdate /*&& latestVersion > buildNumber*/) {
|
||||
status = FORCE_UPDATE;
|
||||
}
|
||||
|
||||
//proceed with status
|
||||
if (status == LOGIN_SUCCESS) {
|
||||
//Set as non fresh install
|
||||
setAsNonFreshInstall(context);
|
||||
|
||||
// simpan app version ketika sukses auth
|
||||
UserSession.setAppVersion(AppContext.getInstance().getVersionCode());
|
||||
|
||||
//Store successfully logged in user's data to GlobalData
|
||||
authenticatedUser.setLogin_id(temp_loginID);
|
||||
authenticatedUser.setPassword(temp_password);
|
||||
String temp_uuid_user = authenticatedUser.getUuid_user();
|
||||
User user = UserDataAccess.getOne(context, temp_uuid_user);
|
||||
if (user != null) {
|
||||
user.setLogin_id(temp_loginID);
|
||||
user.setPassword(temp_password);
|
||||
GlobalData.getSharedGlobalData().setUser(user);
|
||||
} else {
|
||||
GlobalData.getSharedGlobalData().setUser(authenticatedUser);
|
||||
}
|
||||
checkIsEnableLoyalty(generalParameters);
|
||||
if(Global.ENABLE_USER_HELP) {
|
||||
fetchUserHelp(context, generalParameters);
|
||||
}
|
||||
//load theme
|
||||
fetchTheme(context,generalParameters,handler,null, otaLink,
|
||||
needUpdatePassword, pwdExp, softUpdate,
|
||||
message, GlobalData.getSharedGlobalData().getUser());
|
||||
|
||||
} else if (status == FORCE_UPDATE) {
|
||||
handler.onForceUpdate(null, message, otaLink);
|
||||
} else if (status == FORCE_CLEANSING) {
|
||||
handler.onInactiveUser(null);
|
||||
}
|
||||
} else { //login unauthorized
|
||||
handler.onLoginFail(null, message);
|
||||
}
|
||||
|
||||
} else { //fail
|
||||
handler.onConnectionFail(null, connResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void fetchTheme(Context context, List<GeneralParameter> generalParameters,
|
||||
final AuthenticationHandler handler, final Authentication auth, final String otaLink,
|
||||
final boolean needUpdatePassword, final boolean pwdExp,
|
||||
final boolean softUpdate, final String message, final User user) {
|
||||
String themeConfigUrl = null;
|
||||
if(GlobalData.getSharedGlobalData().getApplication().equalsIgnoreCase(Global.APPLICATION_SURVEY)){
|
||||
themeConfigUrl = getGeneralParameter(Global.GS_THEME_CONFIG_SURVEY,generalParameters);
|
||||
}
|
||||
else if(GlobalData.getSharedGlobalData().getApplication().equalsIgnoreCase(Global.APPLICATION_COLLECTION)){
|
||||
themeConfigUrl = getGeneralParameter(Global.GS_THEME_CONFIG_COLLECTION,generalParameters);
|
||||
}
|
||||
else if(GlobalData.getSharedGlobalData().getApplication().equalsIgnoreCase(Global.APPLICATION_ORDER)){
|
||||
themeConfigUrl = getGeneralParameter(Global.GS_THEME_CONFIG_ORDER,generalParameters);
|
||||
}
|
||||
ThemeLoader themeLoader = new ThemeLoader(context);
|
||||
themeLoader.loadThemeFromUrl(themeConfigUrl, new ThemeLoader.ColorSetLoaderCallback() {
|
||||
@Override
|
||||
public void onHasLoaded(DynamicTheme dynamicTheme) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHasLoaded(DynamicTheme dynamicTheme, boolean needUpdate) {
|
||||
handler.onLoginSuccess(auth, otaLink, needUpdatePassword, pwdExp, softUpdate, message, user);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fetchUserHelp(Context context, List<GeneralParameter> generalParameters){
|
||||
String userHelpUrl = null;
|
||||
String commonUserHelpUrl = getGeneralParameter(Global.GS_COMMON_USERHELP_LINK, generalParameters);
|
||||
if(GlobalData.getSharedGlobalData().getApplication().equalsIgnoreCase(Global.APPLICATION_SURVEY)){
|
||||
userHelpUrl = getGeneralParameter(Global.GS_MS_USERHELP_LINK,generalParameters);
|
||||
}
|
||||
else if(GlobalData.getSharedGlobalData().getApplication().equalsIgnoreCase(Global.APPLICATION_COLLECTION)){
|
||||
userHelpUrl = getGeneralParameter(Global.GS_MC_USERHELP_LINK,generalParameters);
|
||||
}
|
||||
else if(GlobalData.getSharedGlobalData().getApplication().equalsIgnoreCase(Global.APPLICATION_ORDER)){
|
||||
userHelpUrl = getGeneralParameter(Global.GS_MO_USERHELP_LINK,generalParameters);
|
||||
}
|
||||
UserHelp.initializeUserHelp(context, commonUserHelpUrl, userHelpUrl);
|
||||
}
|
||||
|
||||
private void checkIsEnableLoyalty(List<GeneralParameter> generalParameters){
|
||||
String gsCode = null;
|
||||
String svyJob = null;
|
||||
if(GlobalData.getSharedGlobalData().getApplication().equalsIgnoreCase(Global.APPLICATION_SURVEY)){
|
||||
gsCode = Global.GS_MS_LOYALTY_ENABLED;
|
||||
svyJob = getGeneralParameter("MS_JOBSVY",generalParameters);
|
||||
}
|
||||
else if(GlobalData.getSharedGlobalData().getApplication().equalsIgnoreCase(Global.APPLICATION_COLLECTION)){
|
||||
gsCode = Global.GS_MC_LOYALTY_ENABLED;
|
||||
}
|
||||
String value = getGeneralParameter(gsCode,generalParameters);
|
||||
if(value == null){
|
||||
Global.LOYALTI_ENABLED = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(value.equals("1")){
|
||||
Global.LOYALTI_ENABLED = true;
|
||||
if(svyJob != null && !svyJob.isEmpty()){
|
||||
svyJob = svyJob.trim();
|
||||
String[] svyJobParts = svyJob.split(";");
|
||||
Global.SLA_LOYALTI_JOB = svyJobParts[0].split(",");
|
||||
}
|
||||
}
|
||||
else {
|
||||
Global.LOYALTI_ENABLED = false;
|
||||
}
|
||||
}
|
||||
|
||||
//=== Setter and Getter ===//
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public AuthenticationHandler getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public void setHandler(AuthenticationHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public boolean isEncrypt() {
|
||||
return encrypt;
|
||||
}
|
||||
|
||||
public void setEncrypt(boolean encrypt) {
|
||||
this.encrypt = encrypt;
|
||||
}
|
||||
|
||||
public boolean isDecrypt() {
|
||||
return decrypt;
|
||||
}
|
||||
|
||||
public void setDecrypt(boolean decrypt) {
|
||||
this.decrypt = decrypt;
|
||||
}
|
||||
|
||||
public static String getTemp_loginID() {
|
||||
return temp_loginID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface to handle authentication result. When authentication is done, user info need to be registered
|
||||
* to GlobalData manually
|
||||
*
|
||||
* @author glen.iglesias
|
||||
*/
|
||||
public interface AuthenticationHandler {
|
||||
|
||||
/**
|
||||
* Called when connection fail
|
||||
*
|
||||
* @param auth
|
||||
* @param result HttpConnectionResult containing error code and reason phrase
|
||||
*/
|
||||
void onConnectionFail(Authentication auth, HttpConnectionResult result);
|
||||
|
||||
/**
|
||||
* Called when server reject credential sent by application
|
||||
*
|
||||
* @param auth
|
||||
* @param message message returned by the server
|
||||
*/
|
||||
void onLoginFail(Authentication auth, String message);
|
||||
|
||||
/**
|
||||
* Called when server force application update
|
||||
*
|
||||
* @param auth
|
||||
* @param message message returned by the server
|
||||
* @param otaLink OTA link to download update
|
||||
*/
|
||||
void onForceUpdate(Authentication auth, String message, String otaLink);
|
||||
|
||||
/**
|
||||
* Called when server report sent credential belong to inactive user
|
||||
*
|
||||
* @param auth
|
||||
*/
|
||||
void onInactiveUser(Authentication auth);
|
||||
|
||||
/**
|
||||
* Called when server has successfully authenticate credential.
|
||||
* Authenticated user need to be registered to GlobalData manually
|
||||
*
|
||||
* @param auth
|
||||
* @param otaLink OTA link to download update, or null if no update needed
|
||||
* @param needUpdatePassword flag if password change is needed
|
||||
* @param message message returned by the server
|
||||
* @param authenticatedUser user info which successfully authenticated with server
|
||||
*/
|
||||
void onLoginSuccess(Authentication auth, String otaLink, boolean needUpdatePassword, boolean pwdExp, boolean needUpdateApplication, String message, User authenticatedUser);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.adins.mss.base.authentication;
|
||||
|
||||
import com.adins.mss.base.BaseCommunicationModel;
|
||||
|
||||
|
||||
/**
|
||||
* JSON Format for authentication
|
||||
*
|
||||
* @author glen.iglesias
|
||||
* @see LoginUserRequest
|
||||
* @deprecated as of 17 Dec 2014, as BaseCommunicationModel
|
||||
*/
|
||||
public class AuthenticationModel extends BaseCommunicationModel {
|
||||
|
||||
protected String password;
|
||||
protected boolean isFreshInstall;
|
||||
|
||||
// public AuthenticationModel(String userId, String password, boolean useDefault, Object additionalData, boolean freshInstall){
|
||||
public AuthenticationModel(String userId, String password, boolean useDefault, boolean freshInstall) {
|
||||
super(useDefault);
|
||||
this.userId = userId;
|
||||
this.password = password;
|
||||
this.isFreshInstall = freshInstall;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package com.adins.mss.base.authentication;
|
||||
|
||||
import com.adins.mss.dao.GeneralParameter;
|
||||
import com.adins.mss.dao.Menu;
|
||||
import com.adins.mss.dao.User;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AuthenticationResultBean {
|
||||
|
||||
private String message;
|
||||
private String otaLink;
|
||||
private String lastUpdateVersion;
|
||||
// private String job;
|
||||
private int loginResult;
|
||||
private boolean isActiveUser;
|
||||
private boolean forceUpdate;
|
||||
private boolean needUpdatePassword;
|
||||
private User userInfo;
|
||||
|
||||
private List<GeneralParameter> generalParameters;
|
||||
|
||||
private List<Menu> listMenu;
|
||||
|
||||
|
||||
public AuthenticationResultBean() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
|
||||
public List<Menu> getListMenu() {
|
||||
return listMenu;
|
||||
}
|
||||
|
||||
|
||||
public void setListMenu(List<Menu> listMenu) {
|
||||
this.listMenu = listMenu;
|
||||
}
|
||||
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
||||
public String getOtaLink() {
|
||||
return otaLink;
|
||||
}
|
||||
|
||||
|
||||
public void setOtaLink(String otaLink) {
|
||||
this.otaLink = otaLink;
|
||||
}
|
||||
|
||||
|
||||
public String getLastUpdateVersion() {
|
||||
return lastUpdateVersion;
|
||||
}
|
||||
|
||||
|
||||
public void setLastUpdateVersion(String lastUpdateVersion) {
|
||||
this.lastUpdateVersion = lastUpdateVersion;
|
||||
}
|
||||
|
||||
|
||||
// public String getJob() {
|
||||
// return job;
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// public void setJob(String job) {
|
||||
// this.job = job;
|
||||
// }
|
||||
|
||||
|
||||
public int getLoginResult() {
|
||||
return loginResult;
|
||||
}
|
||||
|
||||
|
||||
public void setLoginResult(int loginResult) {
|
||||
this.loginResult = loginResult;
|
||||
}
|
||||
|
||||
|
||||
public boolean isActiveUser() {
|
||||
return isActiveUser;
|
||||
}
|
||||
|
||||
|
||||
public void setActiveUser(boolean isActiveUser) {
|
||||
this.isActiveUser = isActiveUser;
|
||||
}
|
||||
|
||||
|
||||
public boolean isForceUpdate() {
|
||||
return forceUpdate;
|
||||
}
|
||||
|
||||
|
||||
public void setForceUpdate(boolean forceUpdate) {
|
||||
this.forceUpdate = forceUpdate;
|
||||
}
|
||||
|
||||
|
||||
public boolean needUpdatePassword() {
|
||||
return needUpdatePassword;
|
||||
}
|
||||
|
||||
|
||||
public void setNeedUpdatePassword(boolean needUpdatePassword) {
|
||||
this.needUpdatePassword = needUpdatePassword;
|
||||
}
|
||||
|
||||
|
||||
public List<GeneralParameter> getGeneralParameters() {
|
||||
return generalParameters;
|
||||
}
|
||||
|
||||
|
||||
public void setGeneralParameters(List<GeneralParameter> generalParameters) {
|
||||
this.generalParameters = generalParameters;
|
||||
}
|
||||
|
||||
|
||||
public User getUserInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
|
||||
public void setUserInfo(User userInfo) {
|
||||
this.userInfo = userInfo;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
package com.adins.mss.base.authentication;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.core.content.FileProvider;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.adins.mss.base.GlobalData;
|
||||
import com.adins.mss.base.R;
|
||||
import com.adins.mss.base.syncfile.FileSyncHelper;
|
||||
import com.adins.mss.base.update.DownloadUpdate;
|
||||
import com.adins.mss.base.util.GsonHelper;
|
||||
import com.adins.mss.base.util.Utility;
|
||||
import com.adins.mss.constant.Global;
|
||||
import com.adins.mss.dao.User;
|
||||
import com.adins.mss.foundation.dialog.DialogManager;
|
||||
import com.adins.mss.foundation.dialog.NiftyDialogBuilder;
|
||||
import com.adins.mss.foundation.http.HttpConnectionResult;
|
||||
import com.adins.mss.foundation.http.MssResponseType;
|
||||
import com.adins.mss.foundation.notification.Notification;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class AuthenticationTask implements Authentication.AuthenticationHandler {
|
||||
public static final String LOGIN_PREFERENES = "login_preferences";
|
||||
public static onImportSuccess importSuccess;
|
||||
private ProgressDialog progressDialog;
|
||||
private FragmentActivity mContext;
|
||||
private Activity activity;
|
||||
|
||||
public AuthenticationTask(FragmentActivity context) {
|
||||
this.mContext = context;
|
||||
Notification.getSharedNotification().clearNotifAll(mContext);
|
||||
progressDialog = ProgressDialog.show(
|
||||
mContext, "",
|
||||
context.getString(R.string.authentication_user), true);
|
||||
String username = GlobalData.getSharedGlobalData().getUser().getLogin_id();
|
||||
String password = GlobalData.getSharedGlobalData().getUser().getPassword();
|
||||
|
||||
PackageInfo pInfo = null;
|
||||
try {
|
||||
pInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
|
||||
} catch (NameNotFoundException e) {
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
}
|
||||
int buildNumber = 0;
|
||||
|
||||
if(pInfo != null) {
|
||||
Global.BUILD_VERSION = pInfo.versionCode;
|
||||
Global.APP_VERSION = pInfo.versionName;
|
||||
buildNumber = Global.BUILD_VERSION;
|
||||
}
|
||||
|
||||
Authentication.authenticateOnBackground(
|
||||
mContext,
|
||||
username,
|
||||
password,
|
||||
buildNumber,
|
||||
this);
|
||||
}
|
||||
|
||||
public AuthenticationTask(Activity context) {
|
||||
this.activity = context;
|
||||
Notification.getSharedNotification().clearNotifAll(mContext);
|
||||
progressDialog = ProgressDialog.show(
|
||||
mContext, "",
|
||||
context.getString(R.string.authentication_user), true);
|
||||
String username = GlobalData.getSharedGlobalData().getUser().getLogin_id();
|
||||
String password = GlobalData.getSharedGlobalData().getUser().getPassword();
|
||||
|
||||
PackageInfo pInfo = null;
|
||||
try {
|
||||
pInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
|
||||
} catch (NameNotFoundException e) {
|
||||
if (Global.IS_DEV)
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int buildNumber = 0;
|
||||
if(pInfo != null){
|
||||
Global.BUILD_VERSION = pInfo.versionCode;
|
||||
Global.APP_VERSION = pInfo.versionName;
|
||||
buildNumber = Global.BUILD_VERSION;
|
||||
}
|
||||
|
||||
Authentication.authenticateOnBackground(
|
||||
mContext,
|
||||
username,
|
||||
password,
|
||||
buildNumber,
|
||||
this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFail(Authentication authentication,
|
||||
HttpConnectionResult httpConnectionResult) {
|
||||
closeProgress();
|
||||
|
||||
//bong 6 may 15 - penjagaan message yang ditampilkan saat login dengan inactive user
|
||||
if (authentication == null) {
|
||||
if (httpConnectionResult != null) {
|
||||
Toast.makeText(
|
||||
mContext,
|
||||
httpConnectionResult.getResult(),
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
} else {
|
||||
Toast.makeText(
|
||||
mContext,
|
||||
mContext.getString(R.string.connection_failed),
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
}
|
||||
return;
|
||||
}
|
||||
//bong 7 may 15 - penjagaan jika belum login ke wifi
|
||||
MssResponseType responseFromServer = null;
|
||||
if (httpConnectionResult.isOK()) {
|
||||
responseFromServer = GsonHelper.fromJson(httpConnectionResult.getResult(), MssResponseType.class);
|
||||
|
||||
if (responseFromServer.getStatus().getCode() == Global.STATUS_CODE_APPL_CLEANSING) {
|
||||
Toast.makeText(
|
||||
mContext,
|
||||
responseFromServer.getStatus().getMessage(),
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Toast.makeText(
|
||||
mContext,
|
||||
mContext.getString(R.string.connection_failed_http) + httpConnectionResult.getStatusCode()
|
||||
+ mContext.getString(R.string.divider_vertical_bar) + httpConnectionResult.getResult(),
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginFail(Authentication auth, String message) {
|
||||
closeProgress();
|
||||
if (message.contains("Password") || message.contains("password") || message.contains("IMEI") || message.contains("imei")) {
|
||||
DialogManager.showForceExitAlert(mContext, mContext.getString(R.string.password_not_match));
|
||||
} else
|
||||
Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onForceUpdate(Authentication auth, String message,
|
||||
String otaLink) {
|
||||
closeProgress();
|
||||
showForceUpdateDialog(otaLink);
|
||||
}
|
||||
|
||||
private void showForceUpdateDialog(final String otaLink) {
|
||||
NiftyDialogBuilder builder = NiftyDialogBuilder.getInstance(mContext)
|
||||
.withTitle(mContext.getString(R.string.server))
|
||||
.withMessage(mContext.getString(R.string.critical_update))
|
||||
.withButton1Text(mContext.getString(R.string.update)).setButton1Click(
|
||||
new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
openUpdate(otaLink);
|
||||
}
|
||||
}
|
||||
).isCancelable(false)
|
||||
.isCancelableOnTouchOutside(false);
|
||||
builder.show();
|
||||
|
||||
}
|
||||
private void openUpdate(String otaLink) {
|
||||
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
File file = new File(mContext.getApplicationContext().getFilesDir(), "app.apk");
|
||||
if (file.exists()) {
|
||||
Uri apkURI = FileProvider.getUriForFile(
|
||||
mContext.getApplicationContext(), mContext.getPackageName() + ".provider", file);
|
||||
intent.setDataAndType(apkURI, "application/vnd.android.package-archive");
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
mContext.startActivity(intent);
|
||||
} else {
|
||||
DownloadUpdate downloadUpdate = new DownloadUpdate(mContext);
|
||||
downloadUpdate.execute(otaLink);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onInactiveUser(Authentication auth) {
|
||||
closeProgress();
|
||||
DialogManager.UninstallerHandler(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginSuccess(Authentication authentication, String otaLink,
|
||||
boolean needUpdatePassword, boolean pwdExp,
|
||||
boolean needUpdateApplication, String message,
|
||||
User authenticatedUser) {
|
||||
closeProgress();
|
||||
importSuccess = new onImportSuccess();
|
||||
if (needUpdateApplication) {
|
||||
showAskForUpdateDialog(otaLink);
|
||||
return;
|
||||
}
|
||||
|
||||
GlobalData.getSharedGlobalData().setUser(authenticatedUser);
|
||||
FileSyncHelper.senderID = 1;
|
||||
FileSyncHelper.startFileSync(mContext);
|
||||
}
|
||||
|
||||
private void goToSynchronize() {
|
||||
Utility.stopAllServices(mContext);
|
||||
Intent syncIntent = Global.syncIntent;
|
||||
mContext.startActivity(syncIntent);
|
||||
mContext.finish();
|
||||
}
|
||||
|
||||
private void showAskForUpdateDialog(final String otaLink) {
|
||||
final NiftyDialogBuilder builder = NiftyDialogBuilder.getInstance(mContext);
|
||||
builder.withTitle(mContext.getString(R.string.server)).isCancelableOnTouchOutside(false).isCancelable(false)
|
||||
.withMessage(mContext.getString(R.string.update_available))
|
||||
.withButton1Text(mContext.getString(R.string.later))
|
||||
.setButton1Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
builder.dismiss();
|
||||
FileSyncHelper.senderID = 1;
|
||||
FileSyncHelper.startFileSync(mContext);
|
||||
}
|
||||
})
|
||||
.withButton2Text(mContext.getString(R.string.update))
|
||||
.setButton2Click(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
builder.dismiss();
|
||||
openUpdate(otaLink);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
private void closeProgress() {
|
||||
if (progressDialog != null && progressDialog.isShowing()) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public class onImportSuccess extends Handler {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
Bundle data = msg.getData();
|
||||
boolean success = data.getBoolean("importSuccess", false);
|
||||
if (success) {
|
||||
goToSynchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.adins.mss.base.authentication;
|
||||
|
||||
import com.adins.mss.dao.GeneralParameter;
|
||||
import com.adins.mss.dao.User;
|
||||
import com.adins.mss.foundation.http.MssResponseType;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JsonLogin extends MssResponseType {
|
||||
|
||||
@SerializedName("user")
|
||||
private User user;
|
||||
@SerializedName("listGeneralParameter")
|
||||
private List<GeneralParameter> listGeneralParameter;
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public List<GeneralParameter> getListGeneralParameter() {
|
||||
return listGeneralParameter;
|
||||
}
|
||||
|
||||
public void setListGeneralParameter(List<GeneralParameter> listGeneralParameter) {
|
||||
this.listGeneralParameter = listGeneralParameter;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue