I am trying to build an app that use google speech cloud api in android kotlin
here is my code
launch {
googleTextToSpeech = TextToSpeechClient.create()
googleTextToSpeech?.let {
viewModel.speakGoogle(googleTextToSpeech!!, totalMessage, player)
}
}
fun speakGoogle(textToSpeech: com.google.cloud.texttospeech.v1.TextToSpeechClient, message: String, player: MediaPlayer) {
val filePath = Environment.getExternalStorageDirectory().absolutePath + "/google_" + System.currentTimeMillis() + ".mp3"
launch {
var msg = android.text.Html.fromHtml(message).toString()
msg = msg.replace("\"", "")
var input = SynthesisInput.newBuilder().setText(msg).build()
var voice = VoiceSelectionParams.newBuilder().setLanguageCode("en-US").setSsmlGender(SsmlVoiceGender.FEMALE).build()
var audio = AudioConfig.newBuilder().setAudioEncoding(AudioEncoding.MP3).build()
var response = textToSpeech.synthesizeSpeech(input, voice, audio)
response?.let {
try {
val inputStream = response.audioContent.toByteArray()
File(filePath).outputStream().use { inputStream }
player.setDataSource(filePath)
player.prepare()
player.start()
} catch (e: IOException) {
Log.i("AMIRA00000", e.toString())
} catch (e: IllegalStateException) {
Log.i("AMIRA00000", e.toString())
}
}
}
}
I am also having my google-service.json file included in the app
but I am getting the following error
java.io.IOException: The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.
at com.google.auth.oauth2.DefaultCredentialsProvider.getDefaultCredentials(DefaultCredentialsProvider.java:134)
at com.google.auth.oauth2.GoogleCredentials.getApplicationDefault(GoogleCredentials.java:119)
at com.google.auth.oauth2.GoogleCredentials.getApplicationDefault(GoogleCredentials.java:91)
at com.google.api.gax.core.GoogleCredentialsProvider.getCredentials(GoogleCredentialsProvider.java:67)
at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:135)
at com.google.cloud.texttospeech.v1.stub.GrpcTextToSpeechStub.create(GrpcTextToSpeechStub.java:74)
at com.google.cloud.texttospeech.v1.stub.TextToSpeechStubSettings.createStub(TextToSpeechStubSettings.java:100)
at com.google.cloud.texttospeech.v1.TextToSpeechClient.<init>(TextToSpeechClient.java:128)
at com.google.cloud.texttospeech.v1.TextToSpeechClient.create(TextToSpeechClient.java:109)
at com.google.cloud.texttospeech.v1.TextToSpeechClient.create(TextToSpeechClient.java:101)
at com.sbs16.ensofia.view.main.MainFragment$setupBinding$3$$special$$inlined$let$lambda$2.invokeSuspend(MainFragment.kt:186)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
I am also having another json file thathave private key and other credential settings but I do not know how to use it
I'm not an Android developer, but my feeling is that you shouldn't call the TextToSpeech directly from your Android app. You should call it through a backend (On AppEngine for example, or on Firebase Functions).
This backend is authenticated by the TextToSpeech API, and your Android client is authenticated on your backend.
Thereby, you can control who use your app, and your TextToSpeech feature. In any case, never put the service account secret key file in your app, either anybody that download you app can steal the key and perform call on the service account behalf and you will pay the bill!
Related
There was a service in framework level, they are binding and starting that service from the framework only. I need to access that service and consume those APIs from the client (Android) side. I have gone through the most of the examples which are having code for create/start service connection from the client and whenever service connected in that connected listener using IBinder, we can access those APIs.
I tried, like adding aidl file at client side with the same package structure and added following code.
val DevManager =applicationContext.getSystemService("servicename")
val clazz = Class.forName(DevManager.javaClass.name)
val method = DevManager.javaClass.getDeclaredMethod(
"getIDevManager",
Context::class.java
)
method.isAccessible = true
val DevService: IDevManager =
method.invoke(DevManager) as IDevManager
var status = DevManager.devStatus
We are getting NoSuchMethodException.
Please suggest how can we achieve this, thanks in advance.
try {
val testManager = TestApplication.context!!.getSystemService(SERVICE_NAME)
val status = testManager.javaClass.getDeclaredMethod("methodName")
status.isAccessible = true
result = (status.invoke(testManager)).toString()
} catch (e: Exception) {
Log.d(TAG, " exception: ${e.message}")
e.printStackTrace()
}
I'm need to get GCLID value inside my android app. What i found is Play Install Referrer Library, that returns me a utm tags, but i'm not sure that GCLID value will be inside val referrer = response.installReferrer
Code sample:
fun getGCLID(){
referrerClient = InstallReferrerClient.newBuilder(this).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
when (responseCode) {
InstallReferrerClient.InstallReferrerResponse.OK -> {
// Connection established.
val response: ReferrerDetails = referrerClient.installReferrer
val referrer = response.installReferrer
val clickTimestamp = response.referrerClickTimestampSeconds
val installTimestamp = response.installBeginTimestampSeconds
Log.d("TagGCLID", "onInstallReferrerSetupFinished: 1")
if ("gclid" in referrer) {
Log.d("TagGCLID", "GCLID is detected in referrer // is $referrer")
//report to Firebase Analytics
} else {
Log.d("TagGCLID", "no GCLID is detected in referrer\n" +
"$referrer")
//do something else
}
}
InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> {
Log.d("TagGCLID", "InstallReferrerResponse: -1")
// API not available on the current Play Store app.
}
InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE -> {
Log.d("TagGCLID", "InstallReferrerResponse: -2")
// Connection couldn't be established.
}
}
}
override fun onInstallReferrerServiceDisconnected() {
Log.d("TagGCLID", "onInstallReferrerServiceDisconnected: -3")
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
}
What i'm suppose to do to get GCLID value?
yes, I also have a similar problem, I can get this gclid if the user has switched from the browser to the play market, but if the advertisement was clicked in the play market itself, then the gclid is not transmitted. Your method is written correctly, but it only works if the user goes through a browser.
I followed the procedure on Google Cloud to register my application by package name with Firebase, installed the resulting google-services.json file in the project’s app folder, and selected the bucket listed in that JSON file with the Kotlin sequence:
val firebaseStorage = Firebase.storage("gs://my-buckets-name.appspot.com")
val pictureRef = firebaseStorage.getReference("first_picture.jpg")
Note: my-buckets-name is not the name of my bucket.
But the upload task fails with a Permisson Denied exception, as shown in the LogCat subwindow.
I have no problem uploading files with the gsutil command on Windows 10 to the same bucket.
I tried making my bucket (briefly!) available allUsers, with NO SUCCESS. Any suggestions for how to debug this would be appreciated. Thanks.
Per a request, here are what I believe are the rules from the Firebase web-based console:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
And what is this "if request.auth != null" all about? What if request.auth is NULL? Where is this set in the Android programming?
The URL is:
https://console.firebase.google.com/project/my-buckets-name/storage/my-buckets-name.appspot.com/rules
Where again I substituted the fake "my-buckets-name" for the real name of the bucket.
And here is the file upload programming from my Android app. Parameter "thePath" is the path to the .JPG I want to upload; path has been verified:
private fun uploadToGoogleCloud(thePath : String)
{
val firebaseStorage = Firebase.storage("gs://my-buckets-name.appspot.com")
val pictureRef = firebaseStorage.getReference("first_picture.jpg")
val theFile = File(thePath)
val uriFile = Uri.fromFile(theFile)
if (uriFile == null) {
display.text = "Failed to get a URI file from " + thePath
return
}
var uploadTask = pictureRef.putFile(uriFile)
uploadTask.addOnFailureListener {
display.text = "Upload to Google Cloud failed: " + it.message //always comes here
}.addOnSuccessListener {
display.text = "Upload to Google Cloud completed"
}
}
I am trying to implement MSAL in Android for logging in user using their Microsoft credentials.
On clean install, first time I am able to get the token, and use it further for accessing Microsoft Graph API.
As expiry time for MSAL token is 1 hour by default, after 1 hour if I try to re-start the app, I face token authentication exception.
Now I am stuck on how to refresh the token again ?
In MSAL I have followed the examples, but nowhere is there any mention of refreshing a token using Android SDK [we can use API calls otherwise to get and refresh token, but I am not using API approach, I am using SDK for handling all the flow.]
I am trying to get through this for some days now.
private val AUTHORITY = "https://login.microsoftonline.com/common"
private var mSingleAccountApp: ISingleAccountPublicClientApplication? = null
private var mActiveAccount: MultiTenantAccount? = null
fun startTokenProcess(
activity: LoginActivity,
preferenceManager: PreferenceManager
) {
this.mActivity = activity
this.mPreferences = preferenceManager
mSingleAccountApp = null
// Creates a PublicClientApplication object with res/raw/auth_config.json
PublicClientApplication.createSingleAccountPublicClientApplication(activity,
R.raw.auth_config,
object : IPublicClientApplication.ISingleAccountApplicationCreatedListener {
override fun onCreated(application: ISingleAccountPublicClientApplication?) {
// initialization of ISingleAccountPublicClientApplication object
mSingleAccountApp = application
// check for existence of any account linked in cache
mSingleAccountApp?.getCurrentAccountAsync(object :
ISingleAccountPublicClientApplication.CurrentAccountCallback {
override fun onAccountLoaded(activeAccount: IAccount?) {
if (activeAccount == null) {
// nothing found
// start new interactive signin
mSingleAccountApp?.signIn(mActivity, "", getScopes(),
object : AuthenticationCallback {
override fun onSuccess(authenticationResult: IAuthenticationResult?) {
mActiveAccount =
authenticationResult?.account as MultiTenantAccount?
// save access token in SP
authenticationResult?.accessToken?.let {
mPreferences.putString(
KEY_ACCESS_TOKEN,
it
)
}
callGraphAPI(authenticationResult?.accessToken)
}
override fun onCancel() {
Timber.d("Canceled")
}
override fun onError(exception: MsalException?) {
Timber.d(exception?.errorCode)
}
})
} else {
// Founded an valid account in cache
// get account token from SP, call Graph API
// todo: check if access token expired ? ask for new token, clear SP
mActiveAccount = activeAccount as MultiTenantAccount?
val accessToken = mPreferences.getString(KEY_ACCESS_TOKEN)
if (accessToken != null) {
callGraphAPI(accessToken)
}
}
}
override fun onAccountChanged(
priorAccount: IAccount?,
currentAccount: IAccount?
) {
Timber.d("Founded an account $priorAccount")
Timber.d("Founded an account $currentAccount")
}
override fun onError(exception: MsalException) {
Timber.e(exception)
}
})
}
override fun onError(exception: MsalException?) {
Timber.e(exception)
}
})
}
I have tried to get token Silently and Interactively again, but no success.
SILENTLY:
mSingleAccountApp?.acquireTokenSilentAsync(getScopes(), AUTHORITY, getAuthSilentCallback())
private fun getAuthSilentCallback(): SilentAuthenticationCallback {
return object : SilentAuthenticationCallback {
override fun onSuccess(authenticationResult: IAuthenticationResult) {
Timber.d("Successfully authenticated")
/* Successfully got a token, use it to call a protected resource - MSGraph */
callGraphAPI(authenticationResult?.accessToken)
}
override fun onError(exception: MsalException) {
/* Failed to acquireToken */
Timber.e("Authentication failed: $exception")
if (exception is MsalClientException) {
Timber.e("Exception inside MSAL, more info inside MsalError.java ")
} else if (exception is MsalServiceException) {
Timber.e("Exception when communicating with the STS, likely config issue")
} else if (exception is MsalUiRequiredException) {
Timber.e("Tokens expired or no session, retry with interactive")
}
}
}
}
OR
INTERACTIVELY:
if (activeAccount == null) {
mSingleAccountApp?.signIn(mActivity, "", getScopes(),
object : AuthenticationCallback {
override fun onSuccess(authenticationResult: IAuthenticationResult?) {
mActiveAccount =
authenticationResult?.account as MultiTenantAccount?
// save access token in SP
authenticationResult?.accessToken?.let {
mPreferences.putString(
KEY_ACCESS_TOKEN,
it
)
}
callGraphAPI(authenticationResult?.accessToken)
}
override fun onCancel() {
Timber.d("Canceled")
}
override fun onError(exception: MsalException?) {
Timber.d(exception?.errorCode)
}
})
}
Edit 1:
Exceptions I am geting:
CoreHttpProvider[sendRequestInternal] - 414Graph service exception Error code: InvalidAuthenticationToken
CoreHttpProvider[sendRequestInternal] - 414Error message: Access token has expired.
CoreHttpProvider[sendRequestInternal] - 414SdkVersion : graph-java/v1.9.0
CoreHttpProvider[sendRequestInternal] - 414Authorization : Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI[...]
CoreHttpProvider[sendRequestInternal] - 414Graph service exception Error code: InvalidAuthenticationToken
Throwable detail: com.microsoft.graph.http.GraphServiceException: Error code: InvalidAuthenticationToken
Error message: Access token has expired.
When I re-try to get token silently, I get the following exception:
l$getAuthSilentCallback: Authentication failed: com.microsoft.identity.client.exception.MsalServiceException: AADSTS700016: Application with identifier 'Some_ID' was not found in the directory 'Some_ID'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.
Trace ID: 'Some_ID'
Correlation ID: 'Some_ID'
Timestamp: 2020-08-15 06:06:11Z
getAuthSilentCallback: Exception when communicating with the STS, likely config issue
Edit 2
As per exceptions I was getting regarding config issue, I got the issue, it was related to the Authority URL which I was using. msal-client-application-configuration
DIAGNOSING
Are there any error details you can provide? And have you traced the HTTPS token refresh message?
WHAT IT SHOULD LOOK LIKE
The MSAL library should be sending a Refresh Token Grant message, as in steps 15 and 16 of my blog post.
My app uses AppAuth libraries but MSAL will work the same way, since that is standard for a mobile app.
I have an app that acts as a service, and the second app needs to connect to it, so I'm using Android Interface Defenition Language (AIDL).
What is the best approach to limit the service accepting only that specific app? and in which method the identity of the client app should happen?
I know a client should have a copy of .aidl file, but I need more ways to check who is connecting to the service.
There are ways to check the identity of the app connecting to your aidl service.
By checking the signing of the apps:
If you want only the apps that are signed by the same key as your app or SystemApps can connect to your service refer kotlin code is below :
Same Key Sign and IsSyetm app:
private fun isSameKeySinged(packageManager: PackageManager, packageNameOfTheOtherApp: String): Boolean {
return packageManager.checkSignatures(
BuildConfig.APPLICATION_ID, packageNameOfTheOtherApp
) == PackageManager.SIGNATURE_MATCH
}
private fun isSystemApp(packageManager: PackageManager, packageNameOfTheOtherApp: String): Boolean {
try {
val applicationInfo = packageManager.getApplicationInfo(
packageNameOfTheOtherApp, 0
)
if (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0 || applicationInfo.flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0) {
return true
}
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
return false
}
By Checking the caller App: You can retrieve the package name of the caller using getCalledId inside the methods which other app call:
val callingApp = packageManager.getNameForUid(Binder.getCallingUid())