Skip to content

Commit 729bbaf

Browse files
committed
v119, Stable
1 parent 7c7a704 commit 729bbaf

6 files changed

Lines changed: 1319 additions & 33 deletions

File tree

.github/workflows/android.yml

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
1-
#name: Android CI/CD
2-
#
3-
#on:
4-
# push:
5-
# branches: [ "master" ]
6-
# pull_request:
7-
# branches: [ "master" ]
8-
#
9-
#jobs:
10-
# build:
11-
# runs-on: ubuntu-latest
12-
# steps:
13-
# - name: Checkout
14-
# uses: actions/checkout@v4.1.1
15-
#
16-
# - name: set up JDK 17
17-
# uses: actions/setup-java@v3
18-
# with:
19-
# java-version: '17'
20-
# distribution: 'adopt'
21-
#
22-
# - name: Grant execute permission for gradlew
23-
# run: chmod +x gradlew
24-
#
25-
# - name: Build with Gradle
26-
# run: ./gradlew build
27-
#
28-
# - name: Upload a Build Artifact
29-
# uses: actions/upload-artifact@v4
30-
# with:
31-
# name: GTI-Test-App.apk
32-
# path: app/build/outputs/apk/debug/app-debug.apk
1+
name: Android CI/CD
2+
3+
on:
4+
push:
5+
branches: [ "master" ]
6+
pull_request:
7+
branches: [ "master" ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4.1.1
15+
16+
- name: set up JDK 17
17+
uses: actions/setup-java@v3
18+
with:
19+
java-version: '17'
20+
distribution: 'adopt'
21+
22+
- name: Grant execute permission for gradlew
23+
run: chmod +x gradlew
24+
25+
- name: Build with Gradle
26+
run: ./gradlew build
27+
28+
- name: Upload a Build Artifact
29+
uses: actions/upload-artifact@v4
30+
with:
31+
name: GTI-Test-App.apk
32+
path: app/build/outputs/apk/debug/app-debug.apk

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
local.properties
1616

1717
# Ignore local library module
18-
/GeoTagImage/src/main/java/com/dangiashish/
18+
#/GeoTagImage/src/main/java/com/dangiashish/
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2023 Ashish Dangi
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.dangiashish
26+
27+
import android.Manifest
28+
import android.content.Context
29+
import android.content.pm.PackageManager
30+
import android.location.Location
31+
import android.os.Handler
32+
import android.os.Looper
33+
import android.util.Log
34+
import android.widget.Toast
35+
import androidx.core.app.ActivityCompat
36+
import com.google.android.gms.location.FusedLocationProviderClient
37+
import com.google.android.gms.location.LocationAvailability
38+
import com.google.android.gms.location.LocationCallback
39+
import com.google.android.gms.location.LocationRequest
40+
import com.google.android.gms.location.LocationResult
41+
import com.google.android.gms.location.LocationServices
42+
import com.google.android.gms.location.Priority
43+
44+
internal object GTILocationUtility {
45+
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
46+
47+
fun fetchLocation(context: Context, callback: (Location?) -> Unit) {
48+
if (fusedLocationProviderClient == null) {
49+
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
50+
}
51+
52+
if (ActivityCompat.checkSelfPermission(
53+
context,
54+
Manifest.permission.ACCESS_FINE_LOCATION
55+
) != PackageManager.PERMISSION_GRANTED ||
56+
ActivityCompat.checkSelfPermission(
57+
context,
58+
Manifest.permission.ACCESS_COARSE_LOCATION
59+
) != PackageManager.PERMISSION_GRANTED
60+
) {
61+
Handler(Looper.getMainLooper()).post {
62+
Toast.makeText(context, "Location permissions are not enabled", Toast.LENGTH_SHORT).show()
63+
}
64+
callback(null)
65+
return
66+
}
67+
68+
fusedLocationProviderClient?.lastLocation
69+
?.addOnSuccessListener { loc ->
70+
if (loc != null) {
71+
callback(loc)
72+
Log.e("LocationUtils", "fetchLocation: $loc")
73+
} else {
74+
requestLiveLocation(context, callback)
75+
}
76+
}
77+
?.addOnFailureListener { err ->
78+
Log.e("LocationUtils", "fetchLocation: ${err.message}")
79+
requestLiveLocation(context, callback)
80+
}
81+
}
82+
83+
private fun requestLiveLocation(context: Context, callback: (Location?) -> Unit) {
84+
val locationRequest = LocationRequest.Builder(
85+
Priority.PRIORITY_HIGH_ACCURACY, 1000L
86+
).setMaxUpdates(1) // Get one update
87+
.build()
88+
89+
if (ActivityCompat.checkSelfPermission(
90+
context,
91+
Manifest.permission.ACCESS_FINE_LOCATION
92+
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
93+
context,
94+
Manifest.permission.ACCESS_COARSE_LOCATION
95+
) != PackageManager.PERMISSION_GRANTED
96+
) {
97+
return
98+
}
99+
fusedLocationProviderClient?.requestLocationUpdates(
100+
locationRequest,
101+
object : LocationCallback() {
102+
override fun onLocationResult(locationResult: LocationResult) {
103+
fusedLocationProviderClient?.removeLocationUpdates(this)
104+
val location = locationResult.lastLocation
105+
callback(location)
106+
Log.e("LocationUtils", "Live Location: $location")
107+
}
108+
109+
override fun onLocationAvailability(locationAvailability: LocationAvailability) {
110+
if (!locationAvailability.isLocationAvailable) {
111+
Log.e("LocationUtils", "Location unavailable")
112+
callback(null)
113+
114+
}
115+
}
116+
},
117+
Looper.getMainLooper()
118+
)
119+
}
120+
121+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2023 Ashish Dangi
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.dangiashish
26+
27+
import android.content.Context
28+
import android.content.pm.ApplicationInfo
29+
import android.content.pm.PackageManager
30+
import android.graphics.Bitmap
31+
import android.graphics.BitmapFactory
32+
import android.media.MediaScannerConnection
33+
import android.net.Uri
34+
import android.os.Environment
35+
import android.util.Log
36+
import androidx.core.content.FileProvider
37+
import androidx.fragment.app.FragmentActivity
38+
import java.io.File
39+
import java.security.cert.Extension
40+
import java.text.SimpleDateFormat
41+
import java.util.Date
42+
import java.util.Locale
43+
44+
object GTIUtility {
45+
private val TAG = "GTIUtility"
46+
47+
/** Check for Map SDK Integration */
48+
@JvmStatic
49+
fun isGoogleMapsLinked(context: Context): Boolean {
50+
val packageManager = context.packageManager
51+
var apiKey: String? = null
52+
try {
53+
val applicationInfo =
54+
packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA)
55+
val metaData = applicationInfo.metaData
56+
if (metaData != null && metaData.containsKey("com.google.android.geo.API_KEY")) {
57+
apiKey = metaData.getString("com.google.android.geo.API_KEY")
58+
}
59+
} catch (e: PackageManager.NameNotFoundException) {
60+
e.printStackTrace()
61+
}
62+
return apiKey != null
63+
}
64+
65+
/** Check for google map api key (if Map SDK is integrated) */
66+
@JvmStatic
67+
fun getMapKey(context: Context): String? {
68+
val packageManager = context.packageManager
69+
var apiKey: String? = null
70+
try {
71+
val applicationInfo =
72+
packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA)
73+
val metaData = applicationInfo.metaData
74+
if (metaData != null && metaData.containsKey("com.google.android.geo.API_KEY")) {
75+
apiKey = metaData.getString("com.google.android.geo.API_KEY")
76+
}
77+
} catch (e: PackageManager.NameNotFoundException) {
78+
e.printStackTrace()
79+
}
80+
return apiKey
81+
}
82+
83+
/** To get application name */
84+
@JvmStatic
85+
fun getApplicationName(context: Context): String {
86+
val packageManager = context.packageManager
87+
val applicationInfo: ApplicationInfo? = try {
88+
packageManager.getApplicationInfo(context.applicationInfo.packageName, 0)
89+
} catch (e: PackageManager.NameNotFoundException) {
90+
null
91+
}
92+
return (if (applicationInfo != null) packageManager.getApplicationLabel(applicationInfo) else "Unknown") as String
93+
}
94+
95+
@Deprecated("")
96+
/** Save original image in camera directory */
97+
@JvmStatic
98+
fun generateOriginalFile(mContext: FragmentActivity, imageExtension: String): File? {
99+
var file: File? = null
100+
Log.i(TAG, "generateOriginalFile: Step 1")
101+
try {
102+
val mediaStorageDir = File(
103+
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
104+
"Camera"
105+
)
106+
Log.w(TAG, "generateOriginalFile: Step 2 : $mediaStorageDir", )
107+
if (!mediaStorageDir.exists()) {
108+
if (!mediaStorageDir.mkdirs()) {
109+
return null
110+
}
111+
}
112+
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmm", Locale.getDefault()).format(Date())
113+
file =
114+
File(mediaStorageDir.path + File.separator + "IMG_" + timeStamp + imageExtension)
115+
} catch (e: Exception) {
116+
e.printStackTrace()
117+
}
118+
if (file != null) {
119+
scanMediaFIle(mContext, file)
120+
}
121+
Log.w(TAG, "generateOriginalFile: Step 3 $file", )
122+
return file
123+
}
124+
125+
private fun scanMediaFIle(mContext: FragmentActivity, file: File) {
126+
MediaScannerConnection.scanFile(
127+
mContext, arrayOf(file.absolutePath),
128+
null
129+
) { _: String?, _: Uri? -> }
130+
}
131+
132+
/** Optimize bitmap to prevent OutOfMemory Exception */
133+
@JvmStatic
134+
fun optimizeBitmap(filePath: String?): Bitmap {
135+
val options = BitmapFactory.Options()
136+
options.inSampleSize = 4
137+
return BitmapFactory.decodeFile(filePath, options)
138+
}
139+
140+
/** get File Uri from application provider */
141+
@JvmStatic
142+
fun getFileUri(context: Context, file: File?): Uri {
143+
return FileProvider.getUriForFile(context, context.packageName + ".provider", file!!)
144+
}
145+
}

0 commit comments

Comments
 (0)