I need to make so background job without blocking the user UI, so I made a test IntentService to check how it works, but this intent service blocks the UI.
In the main app, i am trying to invoke the intent as below,
public void ProcessRequest(IHttpContext context)
{
_isResponseReceived = false;
_context = context;
string[] nodes = context.Request.Url.Split('/');
_intentRequest = context.Request.Body.Parse<IntentRequest>();
_intentActivity.StartActivityForResult(_intentRequest.URL, _intentRequest.Action, _intentRequest.Category, _intentRequest.RequestData, 1);
while (!_isResponseReceived)
{
Thread.Sleep(1500);
}
}
In the app, when invoking the intent call, I am showing the loader and button for the cancel request.
Once I invoke the call, the call gets triggered, but the cancel button is not enabled.
Another app, manifest file where I am using the intent filter, and exposing the service.
Manifest file,
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.app"
android:versionName="1.0.0.0" android:versionCode="1">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:permission=""
android:label="#string/app_name"
android:theme="#style/Theme.Transparent">
<!-- The below two intent filters handle incoming requests from an android app -->
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="org" />
<data
android:host="localhost"
android:port="8080" />
<data android:path="employee/details" />
</intent-filter>
</activity>
<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>
</application>
</manifest>
Related
I have only one app. It has a content provider that is not exported (I don't want other apps to have access to the content) I have successfully been using the content provider until now.
I have created a content observer to update a TextView. The onChange method gets called when the content changes and it tries to re-query that content. That's when it gets the security exception that looks like this:
java.lang.SecurityException: Permission Denial: reading org.sil.lcroffline.data.DataProvider uri content://org.sil.lcroffline/users/by_account_name/5555544444 from pid=0, uid=1000 requires the provider be exported, or grantUriPermission()
Here's the code that generates it:
#Override
public void onChange(boolean selfChange, Uri uri) {
Cursor c = null;
try {
c = mContentResolver.query(UserEntry.buildUserPhoneUri(mAccount.name), null, null, null, null);
// do stuff with the data in the cursor
} finally {
if (c != null) c.close();
}
}
The URI looks like it's formed properly, and I don't think there's a problem with matching it in the content provider.
The code above works fine when called programatically from within the app, it's only when it's triggered by a change in the observed data that the Exception occurs.
How could I get a permission denial from within the same app, and how do I fix this?
Behold the manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.sil.lcroffline">
<!-- To communicate with LCR -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Required because we're manually creating a new account. -->
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".authentication.LoginActivity"
android:label="#string/app_name"
android:exported="true">
</activity>
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main"
android:theme="#style/AppTheme.NoActionBar"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ReportActivity"
android:parentActivityName=".MainActivity"></activity>
<service android:name=".authentication.AuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="#xml/authenticator" />
</service>
<provider
android:authorities="#string/data_authority"
android:name=".data.DataProvider"
android:exported="false" />
<service
android:name=".data.SyncService"
android:exported="true"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="#xml/syncadapter" />
</service>
</application>
</manifest>
It turns out this is caused by me not using a Handler in the ContentObserver
When you don't pass a handler to the content observer the onChange method gets called directly instead of a message to call it being posted through the handler. This is all well and good, except that the process that calls the onChange method in that situation is the System OS, which doesn't have the necessary permissions to query my content provider.
To fixed this I changed the code where my content observer is created from this:
mUserObserver = new ContentObserver(null) {
// override onChange methods here
}
To this:
mUserObserver = new ContentObserver(new Handler()) {
// override onChange methods here
}
I was clued in by this question
I've almost made my sms app, only one bug still remains. When phone receives incoming sms it somehow goes to my app and to default one. I thought that problem was in action of intent, but changing it does nothing. The question is - how to intercept incoming sms and forbid default app to do the same?
AndroidManifest:
<manifest package="lexzcq.com.smska"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission
android:name="android.permission.SET_PREFERRED_APPLICATIONS"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<application
android:allowBackup="true"
android:icon="#drawable/logo"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:theme="#style/Theme.AppCompat.Light.NoActionBar">
<intent-filter android:priority="999">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.APP_MESSAGING"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<receiver
android:name=".SmsReceiver"
android:permission="android.permission.BROADCAST_SMS"
>
<intent-filter android:priority="999">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
<category android:name="android.intent.category.APP_MESSAGING"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<activity android:name=".ChatWindow">
<intent-filter>
<action android:name="com.lexzcq.com.lexzcq.sms_receive_intent"/>
</intent-filter>
</activity>
<application android:name=".MyApp">
</application>
</application>
</manifest>
SmsReceiver.class
public class SmsReceiver extends BroadcastReceiver {
#Override
public void onReceive (Context context, Intent intent) {
*//here I handle sms from pdus*
Intent broadcastIntent = new Intent ()
.putExtra ("address", address)
.putExtra ("body", body)
.setAction ("com.lexzcq.sms_receive_intent");
*//here I'm writing sms to database*
context.sendBroadcast (broadcastIntent);
abortBroadcast ();
}
}
}
If needed - I can provide broadcast receivers from MainActivity.class
P.S. Most weird part - that when I'm sending sms it somehow saves to default app but I didn't broadcast it with SMS_RECEIVED_ACTION.
I have a broadcast receiver that works when I set it up dynamically, but does not work when declared in a manifest file.
I've googled for this and all the examples match what I'm doing in my code. I do have an activity in my manifest file, so that can't be the problem. I've tried fully specifying the receiver class name as well as using .MyBroadcastReceiver but that did not make any difference.
Can someone help?
Here is my manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mikrodyne.receiverdemo" >
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.mikrodyne.receiverdemo.MyBroadcastReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.HEADSET_PLUG" />
</intent-filter>
</receiver>
</application>
</manifest>
And here is my receiver class
public class MyBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
Log.d("Receiver", "Received action: " + action);
}
}
TIA
Nisha Miller
As per the documentation for HEADSET_PLUG:
You cannot receive this through components declared in manifests, only by explicitly registering for it with Context.registerReceiver().
So what you're trying to do is not possible.
If you want to get events from outside, you need to set android:exported="true"
Note: you can't get that intent.
Put this in your AndroidManifest.xml
<receiver
android:name="com.mikrodyne.receiverdemo.MyBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.HEADSET_PLUG" />
</intent-filter>
</receiver>
I have the next code in my Android Studio project
#Override
public void startActivity(Intent intent) {
boolean bandera = Intent.ACTION_SEARCH.equals(intent.getAction()) || RecognizerIntent.ACTION_RECOGNIZE_SPEECH.equals(intent.getAction());
if (bandera) {
intent.putExtra("usuario", usuarioIS);
}
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
super.startActivity(intent);
}
When I search, I use the putExtra method to send some info of a user from the actual activity to another activity. But when I use the speech recognition, the startActivity method throws me an exception in my phone and android studio doesn't give info about the exception. Does anyone know why the speech recognition does not work?
This is my Manifest.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.ivan.saberespoder" >
<!-- To access Google+ APIs: rex -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- To retrieve OAuth 2.0 tokens or invalidate tokens to disconnect a user. This disconnect *** option is required to comply with the Google+ Sign-In developer policies -->
<uses-permission android:name="android.permission.USE_CREDENTIALS" /> <!-- To retrieve the account name (email) as part of sign-in: -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> <!-- To auto-complete the email text field in the login form with the user's emails -->
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<activity
android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="#string/app_name"
android:theme="#android:style/Theme.Translucent.NoTitleBar" />
<application
android:allowBackup="true"
android:icon="#mipmap/logopeq"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="#string/facebook_app_id" />
<activity
android:name=".PantallaPrincipal"
android:label="iShots" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value=".Busqueda" />
</activity>
<activity
android:name=".Busqueda"
android:label="#string/title_activity_busqueda" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
</activity>
<activity
android:name=".LoginActivity"
android:label="#string/title_activity_login"
android:windowSoftInputMode="adjustResize|stateHidden" >
</activity>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name=".Registro"
android:label="#string/title_activity_menu_usuario" >
</activity>
<activity
android:name=".MostrarShot"
android:label="#string/title_activity_mostrar_shot" >
</activity>
<activity
android:name=".Settings"
android:label="#string/title_activity_settings" >
</activity>
<activity
android:name=".AgregarShot"
android:label="#string/title_activity_agregar_shot" >
</activity>
<activity
android:name=".ProfileActivity"
android:label="#string/title_activity_profile" >
</activity>
<activity
android:name=".HelpActivity"
android:label="#string/title_activity_help" >
</activity>
<activity
android:name=".AboutActivity"
android:label="#string/title_activity_about" >
</activity>
</application>
</manifest>
I'm new using Android Studio
public static final String ACTION_RECOGNIZE_SPEECH
Added in API level 3 Starts an activity that will prompt the user for
speech and send it through a speech recognizer. The results will be
returned via activity results (in onActivityResult(int, int, Intent),
if you start the intent using startActivityForResult(Intent, int)), or
forwarded via a PendingIntent if one is provided.
Starting this intent with just startActivity(Intent) is not supported.
You must either use startActivityForResult(Intent, int), or provide a
PendingIntent, to receive recognition results.
Doc source
So try dealing with startActivityForResult();
Secondly, you should add a permission to Manifest :
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Third, if you define Action RecognizerIntent.ACTION_RECOGNIZE_SPEECH, so the system will try to open Activity which can handle it. So for your next Activity you should add this "skill" to Manifest. Source. If you don't want, just handle this Activity as usual with Intent.ACTION_VIEW.
One nice answer for you in addition. This will fit you I guess.
Try it out. Hope it helps.
Hello fellow programmers,
I cant find a proper way to route my application, I would like one file to decide which activity has to be started
I am building an android application that in general contains:
-2 ways to start up
-3 activity's
The application can be launched by clicking the icon (standard launch)
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
And an activity is started when there is an incoming call
<action android:name="android.intent.action.PHONE_STATE" />
In the first setup there was 2 activity's one to register and one to use the application. In this
setup I added an extra activity to check if a token was present and route to the right activity.
In the setup that I have now, all the actions are in the of a broadcast receiver. I tried implementing the logic of the extra activity.
The problem I am facing is the check of the incoming call, it is always launching the same activity CallHandler,
I think routing the application within a broadcast receiver might be bad practice, but I can not find a better way of routing the application, and the current code does not work.
Your help is very much appreciated, the following pieces of code might help explain my issue:
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name=".RoutingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</receiver>
<activity
android:name=".RegisterActivity"
android:label="#string/app_name"
android:windowSoftInputMode="adjustResize|stateVisible" >
</activity>
<activity
android:name=".CallHandler"
android:label="#string/title_activity_main" >
</activity>
<activity
android:name=".CreateCallActivity"
android:label="#string/title_activity_create_call" >
</activity>
</application>
RoutingCallReceiver:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
public class RoutingCallReceiver extends BroadcastReceiver {
TelephonyManager telephony;
Intent in;
public void onReceive(Context context, Intent intent) {
PrimePhoneStateListener phoneListener = new PrimePhoneStateListener();
telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
if(telephony.getCallState()== 1){
in = new Intent(context, CallHandler.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(in);
}
else {
TokenIO tokenHandler = new TokenIO();
String token = tokenHandler.getToken(context);
Log.d("AAfter", "Token");
if(token.equals("") || token.equals(null)){
in = new Intent(context, RegisterActivity.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(in);
}
else{
in = new Intent(context, CreateCallActivity.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(in);
}
}
}
// when finish your job, stop listen to changes
public void onDestroy() {
telephony.listen(null, PhoneStateListener.LISTEN_NONE);
}
}
you can make change in your xml file
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name=".RoutingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<activity
android:name=".RegisterActivity"
android:label="#string/app_name"
android:windowSoftInputMode="adjustResize|stateVisible" >
</activity>
<activity
android:name=".CallHandler"
android:label="#string/title_activity_main" >
</activity>
<activity
android:name=".CreateCallActivity"
android:label="#string/title_activity_create_call" >
</activity>
</application>
and put this tag into main activity
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
and i hope that will work fine.