Force stop android applications - android

After opening application details settings using
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS), how can I force stop application programmatically?

You can use Accessibility to achieve that (but it needs Accessibility for your app turned on by user)
public class MyAccessibilityService extends AccessibilityService {
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
//TYPE_WINDOW_STATE_CHANGED == 32
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event
.getEventType()) {
AccessibilityNodeInfo nodeInfo = event.getSource();
if (nodeInfo == null) {
return;
}
List<AccessibilityNodeInfo> list = nodeInfo
.findAccessibilityNodeInfosByViewId("com.android.settings:id/left_button");
//We can find button using button name or button id
for (AccessibilityNodeInfo node : list) {
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
list = nodeInfo
.findAccessibilityNodeInfosByViewId("android:id/button1");
for (AccessibilityNodeInfo node : list) {
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
#Override
public void onInterrupt() {
// TODO Auto-generated method stub
}
}
You can check it out in this example:
AccessibilityTestService.java

You have two ways, a more rude one and a better one
The good practice
If you have only one activity running
the this.finish(); method will be enough
If you have multiple activities running
You gotta call the this.finishAffinity(); method. This is the best practice in general cases, where you can have both a single or multiple activities
The rude way
System.Exit(0);
I added this only for info, but this might not work with multiple activities and this is not a good way for closing apps. It's mostly like the "Hold power button until the pc shuts down".

Clicking an element of another application on runtime is something that will be considered as a security threat. You would need a hack to go past this hurdle.
There is one hack that I recently found out, you can probably make use of it. You can find the source code here: https://github.com/tfKamran/android-ui-automator
You can add the code in here as a module in your app and invoke a service with action com.tf.uiautomator.ACTION_CLICK_ITEM and send the text of the element you want to click on as an extra with key itemText.
You can test it using adb like:
adb shell am startservice -a com.tf.uiautomator.ACTION_CLICK_ITEM -e itemText "OK"

I found one solution for force stop. After force stop how can i go back to my activity page ?
public class DeviceAccessibilityService extends AccessibilityService {
private static final String TAG = "litan";
private boolean isKilled = false;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
isKilled = false;
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType()) {
AccessibilityNodeInfo nodeInfo = event.getSource();
Log.i(TAG, "ACC::onAccessibilityEvent: nodeInfo=" + nodeInfo);
if (nodeInfo == null) {
return;
}
List<AccessibilityNodeInfo> list = new ArrayList<>();
if ("com.android.settings.applications.InstalledAppDetailsTop".equals(event.getClassName())) {
if (Build.VERSION.SDK_INT >= 18) {
list = nodeInfo.findAccessibilityNodeInfosByViewId("com.android.settings:id/right_button");
} else if (Build.VERSION.SDK_INT >= 14) {
list = nodeInfo.findAccessibilityNodeInfosByText("com.android.settings:id/right_button");
}
for (AccessibilityNodeInfo node : list) {
Log.i(TAG, "ACC::onAccessibilityEvent: left_button " + node);
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
} else if ("android.app.AlertDialog".equals(event.getClassName())) {
list = new ArrayList<>();
if (Build.VERSION.SDK_INT >= 18) {
list = nodeInfo.findAccessibilityNodeInfosByViewId("android:id/button1");
} else if (Build.VERSION.SDK_INT >= 14) {
list = nodeInfo.findAccessibilityNodeInfosByText("android:id/button1");
}
for (final AccessibilityNodeInfo node : list) {
Log.i(TAG, "ACC::onAccessibilityEvent: button1 " + node);
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
//node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
return;
}
}
#Override
public void onInterrupt() {
// TODO Auto-generated method stub
Log.i("Interrupt", "Interrupt");
}
#Override
protected void onServiceConnected() {
AccessibilityServiceInfo info = getServiceInfo();
info.eventTypes = AccessibilityEvent.TYPE_WINDOWS_CHANGED | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
info.flags = AccessibilityServiceInfo.DEFAULT;
info.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
info.flags = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS;
info.flags = AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
info.flags = AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
// We are keeping the timeout to 0 as we don’t need any delay or to pause our accessibility events
info.feedbackType = AccessibilityEvent.TYPES_ALL_MASK;
info.notificationTimeout = 100;
this.setServiceInfo(info);
// Toast.makeText(getApplicationContext(), "onServiceConnected", Toast.LENGTH_SHORT).show();
}
private static void logd(String msg) {
Log.d(TAG, msg);
}
private static void logw(String msg) {
Log.w(TAG, msg);
}
private static void logi(String msg) {
Log.i(TAG, msg);
}
}

Related

android accessibility : Get all EditText node in a webview

I am trying to create a password app manager. I want to create an Autofill feature.
I saw Android autofill, but it doesnt work perfectly on browser app. So I decided to use the accessiblity to get all editText.
If I find 2 EditText including one in password mode, I enable autofill. (I suppose it is a login form)
When I loop into all nodes in the view, I will only find the EditText focused.it's like this I couldn't find all the node.
Is there a way to find all the node of the screen for a browser app?
Here is the code
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
switch(event.getEventType()) {
case AccessibilityEvent.TYPE_VIEW_CLICKED:
case AccessibilityEvent.TYPE_VIEW_FOCUSED:
try {
if(event.getClassName() == null) return;
Log.e(TAG, "onAccessibilityEvent: " + getEventType(event) );
Class className = Class.forName(event.getClassName().toString());
if (EditText.class.isAssignableFrom(className)) {
/** parse ALL NODE -> see getCredFieldsFromViews **/
Log.i(TAG + "-info", AccessiblityParser.getInfoFromEvent(getRootInActiveWindow()).toString());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
break;
}
}
#Override
public void onServiceConnected() {
AccessibilityServiceInfo info = getServiceInfo();
info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_ALL_MASK; //.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
info.flags = AccessibilityServiceInfo.DEFAULT | AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS |
AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE | AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS
| AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS;
//info.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS ;
info.notificationTimeout = 100;
this.setServiceInfo(info);
}
Loop all the nodes :
private static void getCredFieldsFromViews(AccessiblityParser accessiblityParser,AccessibilityNodeInfo info) throws ClassNotFoundException {
if (info == null)
return;
if(info.isEditable()){
if( info.isPassword() ){ // password EDIT TEXT
accessiblityParser.mdpNode = info;
}else{ // (maybe) username EDIT TEXT
accessiblityParser.usernameNode = info;
}
}
int childCount = info.getChildCount();
for(int i=0;i<childCount;i++){
AccessibilityNodeInfo child = info.getChild(i);
if(child != null)
child.refresh();
getCredFieldsFromViews(accessiblityParser,child);
if(child != null){
child.recycle();
}
test++;
}
return;
}
EDIT :
I saw Accessibility and Android WebView
Maybe I can inject script if it is not deprecated ?
Another way maybe use :
arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "INPUT");
r = info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
But how to use it ?
Thank

Click on the Notification programmatically

I trying click on the notification after receiving it.
I'm able to drag the notification drawer using the Accessibility service.
For clicking the notification I'm using accessibilityEvent.getSource() and
accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
My code:
public class MyAccessibilityService extends AccessibilityService {
/**
* On receiving the AccessibilityEvent performs the Actions
*
* #param event
*/
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.i(TAG, "Get the Accessibility Event");
if (event.getEventType() == AccessibilityEvent.TYPE_TOUCH_INTERACTION_END) {
handleTypeTouchInteractionEndEvents(event);
}
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
handleTypeWindowStateChangedEvents(event);
}
}
#Override
public void onServiceConnected() {
AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPE_TOUCH_INTERACTION_END | AccessibilityEvent.TYPE_VIEW_CLICKED |
AccessibilityEvent.TYPE_VIEW_FOCUSED | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES;
accessibilityServiceInfo.flags = AccessibilityServiceInfo.DEFAULT | AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
accessibilityServiceInfo.notificationTimeout = NOTIFICATION_TIME_OUT;
this.setServiceInfo(accessibilityServiceInfo);
}
#Override
public void onInterrupt() {
//Do Nothing
}
/**
* Performs the action for TYPE_TOUCH_INTERACTION_END events
*
* #param accessibilityEvent
*/
private void handleTypeTouchInteractionEndEvents(AccessibilityEvent accessibilityEvent) {
switch (accessibilityEvent.getAction()) {
case EXPAND_NOTIFICATIONS_DRAWER:
Log.i(TAG, "perfroming expand notification bar"); performGlobalAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
break;
default:
Log.i(TAG, "Event type not defined");
}
}
private void handleTypeWindowStateChangedEvents(AccessibilityEvent accessibilityEvent) {
switch (accessibilityEvent.getAction()) {
case ACTION_CLICK:
Log.i(TAG, "Performing click Action");
findNotificationIconAndClick("com.my.app:id/notification_icon", accessibilityEvent);
Log.i(TAG, "Click Action is successfull");
default:
Log.i(TAG, "Event type not defined");
}
}
public void findNotificationIconAndClick(String id, AccessibilityEvent accessibilityEvent) {
AccessibilityNodeInfo accessibilityNodeInfo = accessibilityEvent.getSource();
List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);
if (nodeInfoList != null && !nodeInfoList.isEmpty()) {
for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
if (nodeInfo != null) {
performClick(nodeInfo);
break;
}
}
}
}
}
I'm new to using accessibility service. Can someone tell me if there is any mistake from my side or if it is not possible to click on a notification using accessibility service? Are there any other possibilities without using Accessibility Service to click on the Notification?
If you want to click on the notification, you have to extend the NotificationListenerService, implement what have to be implemented then you can call sbn.getNotification().contentIntent.send(). This way is like if user was clicking on the notification from the notification tray.
Not all accessibility events will return a source. In fact, most (or at least the events that occur most frequently) do not. Make sure you're limiting to a reasonable subset of events in your configuration AND/OR doing a null check on event.getSource().

NFC tag(for NfcA) scan works only from the second time

I wrote a custom plugin to read blocks of data from an NfcA(i.e.non-ndef) tag. It seems to work fine , but only after the second scan. I am using Activity intent to derive the "NfcAdapter.EXTRA_TAG" to later use it for reading the values. I am also updating the Intents in onNewIntent(). OnNewIntent gets called after the second scan and after that I get result all the time.But in the first scan onNewIntent does not gets called, hence I end up using the Activity tag that does not have "NfcAdapter.EXTRA_TAG", hence I get null. Please see the my code below.
SE_NfcA.java(my native code for plugin)
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
String Result = "";
String TypeOfTalking = "";
if (action.contains("TalkToNFC"))
{
JSONObject arg_object = args.getJSONObject(0);
TypeOfTalking = arg_object.getString("type");
if(TypeOfTalking != "")
{
if (TypeOfTalking.contains("readBlock"))
{
if(TypeOfTalking.contains("#"))
{
try
{
String[] parts = TypeOfTalking.split("#");
int index = Integer.parseInt(parts[1]);
Result = Readblock(cordova.getActivity().getIntent(),(byte)index);
callbackContext.success(Result);
}
catch(Exception e)
{
callbackContext.error("Exception Reading "+ TypeOfTalking + "due to "+ e.toString());
return false;
}
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
return true;
}
#Override
public void onNewIntent(Intent intent) {
ShowAlert("onNewIntent called");
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
super.onNewIntent(intent);
getActivity().setIntent(intent);
savedTag = tagFromIntent;
savedIntent = intent;
}
#Override
public void onPause(boolean multitasking) {
Log.d(TAG, "onPause " + getActivity().getIntent());
super.onPause(multitasking);
if (multitasking) {
// nfc can't run in background
stopNfc();
}
}
#Override
public void onResume(boolean multitasking) {
Log.d(TAG, "onResume " + getActivity().getIntent());
super.onResume(multitasking);
startNfc();
}
public String Readblock(Intent Intent,byte block) throws IOException{
byte[] response = new byte[]{};
if(Intent != null)
{
Tag myTag = Intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(savedTag != null)
myTag = savedTag;
if(myTag != null)
{
try{
Reader nTagReader = new Reader(myTag);
nTagReader.close();
nTagReader.connect();
nTagReader.SectorSelect(Sector.Sector0);
response = nTagReader.fast_read(block, block);
nTagReader.close();
return ConvertH(response);
}catch(Exception e){
ShowAlert(e.toString());
}
}
else
ShowAlert("myTag is null.");
}
return null;
}
private void createPendingIntent() {
if (pendingIntent == null) {
Activity activity = getActivity();
Intent intent = new Intent(activity, activity.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
}
}
private void startNfc() {
createPendingIntent(); // onResume can call startNfc before execute
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null && !getActivity().isFinishing()) {
try {
nfcAdapter.enableForegroundDispatch(getActivity(), getPendingIntent(), getIntentFilters(), getTechLists());
if (p2pMessage != null) {
nfcAdapter.setNdefPushMessage(p2pMessage, getActivity());
}
} catch (IllegalStateException e) {
// issue 110 - user exits app with home button while nfc is initializing
Log.w(TAG, "Illegal State Exception starting NFC. Assuming application is terminating.");
}
}
}
});
}
private void stopNfc() {
Log.d(TAG, "stopNfc");
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null) {
try {
nfcAdapter.disableForegroundDispatch(getActivity());
} catch (IllegalStateException e) {
// issue 125 - user exits app with back button while nfc
Log.w(TAG, "Illegal State Exception stopping NFC. Assuming application is terminating.");
}
}
}
});
}
private Activity getActivity() {
return this.cordova.getActivity();
}
private PendingIntent getPendingIntent() {
return pendingIntent;
}
private IntentFilter[] getIntentFilters() {
return intentFilters.toArray(new IntentFilter[intentFilters.size()]);
}
private String[][] getTechLists() {
//noinspection ToArrayCallWithZeroLengthArrayArgument
return techLists.toArray(new String[0][0]);
}
}
My index.js file
nfc.addTagDiscoveredListener(
function(nfcEvent){
console.log(nfcEvent.tag.id);
alert(nfcEvent.tag.id);
window.echo("readBlock#88");//call to plugin
},
function() {
alert("Listening for NFC tags.");
},
function() {
alert("NFC activation failed.");
}
);
SE_NfcA.js(plugin interface for interaction b/w index.js and SE_NfcA.java)
window.echo = function(natureOfTalk)
{
alert("Inside JS Interface, arg =" + natureOfTalk);
cordova.exec(function(result){alert("Result is : "+result);},
function(error){alert("Some Error happened : "+ error);},
"SE_NfcA","TalkToNFC",[{"type": natureOfTalk}]);
};
I guess I have messed up with the Intents/Activity Life-Cycle, please help. TIA!
I found a tweak/hack and made it to work.
Before making any call to read or write, I made one dummy Initialize call.
window.echo("Initialize");
window.echo("readBlock#88");//call to plugin to read.
And in the native code of the plugin, on receiving the "Initialize" token I made a startNFC() call.
else if(TypeOfTalking.equalsIgnoreCase("Initialize"))
{
startNfc();
}

Launching an intent without context

What is the best way to deal with the following situation:
I have a IntentService which does synchronisation with the server (this is triggered by either an Activity coming to the foreground, or a GCM message, so onoy occasional). Sometimes there is a user action needed as a result, and the given command/request is part of the response XML.
There are basically two options, it is either a yes/no question, or a full Activity to for example select the desired language.
How can I do this, or what would be the best way? If I try to launch the Activity with the context of the IntentService nothing happens. I could write a abstract Activity, which I extends in all my Activities and sent a broadcast message which those receive and subsequent start the Activity form the activity which is active, but don't know if that is the best way to do it in Android.
Any suggestions would be appreciated!
[EDIT: as suggested some code]
public class SyncService extends IntentService{
public SyncService(){
super("SyncService");
}
#Override
protected void onHandleIntent(Intent intent) {
iDomsAndroidApp app = ((iDomsAndroidApp) getApplicationContext());
DataManager manager = app.getDataManager();
manager.updateData(this);
}
}
public class DataManager {
// For brevity, this is called with the DOM.Document with the actions to be preformed
private void checkForActions(Document doc, SyncUpdateInterface syncInterface){
NodeList objects = null;
NodeList rootNodes = doc.getElementsByTagName("actions");
for (int j = 0; j < rootNodes.getLength(); j++) {
Element rootElement = (Element) rootNodes.item(j);
if (!rootElement.getParentNode().getNodeName().equals("iDoms")) {
continue;
}
objects = ((Element) rootNodes.item(j)).getElementsByTagName("action");
break;
}
if(objects == null || objects.getLength() == 0){
Log.d(iDomsAndroidApp.TAG, "No actions");
return;
}
for (int j = 0; j < objects.getLength(); j++) {
Element element = (Element) objects.item(j);
String action = ((Element) element.getElementsByTagName("command").item(0)).getTextContent();
if(action == null) return;
Log.d(iDomsAndroidApp.TAG, "Action: " + action);
try{
if(action.equalsIgnoreCase("selectLanguage")){
if(syncInterface == null || syncInterface.getContext() == null) throw new Exception("No context, so cannot perform action");
iDomsAndroidApp app = ((iDomsAndroidApp) iDomsAndroidApp.getAppContext());
// The app.actionIntent is just a central function to pick the right intent for an action.
syncInterface.getContext().startActivity(app.actionIntent("settings", iDomsAndroidApp.context));
} else if (action.equalsIgnoreCase("markAllAsRead")) {
if(syncInterface == null | syncInterface.getContext() == null) throw new Exception("No context, so cannot perform action");
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(syncInterface.getContext());
alertDialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
// User clicked OK, so save the result somewhere
// or return them to the component that opened the dialog
iDomsAndroidApp app = ((iDomsAndroidApp) iDomsAndroidApp.getAppContext());
app.getDataManager().markAllAsRead(null);
}
});
alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
}
});
alertDialogBuilder.setTitle(iDomsAndroidApp.context.getString(R.string.markAllAsRead));
alertDialogBuilder.setMessage(iDomsAndroidApp.context.getString(R.string.markAllAsReadText));
alertDialogBuilder.show();
}
} catch (Exception e){
Log.w(iDomsAndroidApp.TAG, "Problem performing the action " + element.getTextContent(), e);
sentCrashReport("Problem performing the action " + element.getTextContent(), e);
}
}
}
I tried using the my SyncInterface, as it gives the context of the IntentService, but think it is a but clumsy and doesn't work:
public interface SyncUpdateInterface {
public void doProgress(String message, int increment, int total);
public void doProgress(String message, int increment);
public void doProgress(String message);
public Context getContext();
}
You might have to rethink your approach. The intentservice only lives for the duration of the onHandleIntent() method. That is to say, once the last line of code of the onHandleIntent() method is reached, the IntentService stops itself.
Try EventBus. It provides a solution to similar problems by making communication between components (Activities, Services, Standalone classes) of an application.
Use Gradle to import library
compile 'org.greenrobot:eventbus:3.1.1'
Define an event
public class MessageEvent { /* Additional fields if needed */ }
Launch Event using
EventBus.getDefault().post(new MessageEvent());
Register component to receive event
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
Receive launched even by declaring this method
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
For more information visit https://github.com/greenrobot/EventBus

How to integrate SIP into Android?

How to implement SIP protocol in Android ?
there is any SDK or library available to implement it easily into Android?
Here is a third party Library with sample code. You can use this, I have used it and it works fine.
Android 2.3 or higher provides API for SIP.
Refer this link for SIP in Android
also you can see DEMO project for SIP from Sample
update:
Android SDK Samples on github.
SipDemo1, SipDemo2
Search for SipDemo project in samples for android 4.0.3 SDK version(API level -15)
I have been investigated this sort of problem for a long time and found out that SipManager and SipProfile are unfortunatelly poor and extremelly buggy.
So I found a Linphone library. There is a link for their wiki. I implemented it in my project using maven:
repositories {
...
maven { "https://linphone.org/maven_repository/"}
}
Also there is a sample of using it on gitlab: link here, it's pretty fresh, for now :)
If the link would crash, I just copy/paste the most important part of how to use linphone's core:
public class LinphoneService extends Service {
private static final String START_LINPHONE_LOGS = " ==== Device information dump ====";
// Keep a static reference to the Service so we can access it from anywhere in the app
private static LinphoneService sInstance;
private Handler mHandler;
private Timer mTimer;
private Core mCore;
private CoreListenerStub mCoreListener;
public static boolean isReady() {
return sInstance != null;
}
public static LinphoneService getInstance() {
return sInstance;
}
public static Core getCore() {
return sInstance.mCore;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
// The first call to liblinphone SDK MUST BE to a Factory method
// So let's enable the library debug logs & log collection
String basePath = getFilesDir().getAbsolutePath();
Factory.instance().setLogCollectionPath(basePath);
Factory.instance().enableLogCollection(LogCollectionState.Enabled);
Factory.instance().setDebugMode(true, getString(R.string.app_name));
// Dump some useful information about the device we're running on
Log.i(START_LINPHONE_LOGS);
dumpDeviceInformation();
dumpInstalledLinphoneInformation();
mHandler = new Handler();
// This will be our main Core listener, it will change activities depending on events
mCoreListener = new CoreListenerStub() {
#Override
public void onCallStateChanged(Core core, Call call, Call.State state, String message) {
Toast.makeText(LinphoneService.this, message, Toast.LENGTH_SHORT).show();
if (state == Call.State.IncomingReceived) {
Toast.makeText(LinphoneService.this, "Incoming call received, answering it automatically", Toast.LENGTH_LONG).show();
// For this sample we will automatically answer incoming calls
CallParams params = getCore().createCallParams(call);
params.enableVideo(true);
call.acceptWithParams(params);
} else if (state == Call.State.Connected) {
// This stats means the call has been established, let's start the call activity
Intent intent = new Intent(LinphoneService.this, CallActivity.class);
// As it is the Service that is starting the activity, we have to give this flag
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
};
try {
// Let's copy some RAW resources to the device
// The default config file must only be installed once (the first time)
copyIfNotExist(R.raw.linphonerc_default, basePath + "/.linphonerc");
// The factory config is used to override any other setting, let's copy it each time
copyFromPackage(R.raw.linphonerc_factory, "linphonerc");
} catch (IOException ioe) {
Log.e(ioe);
}
// Create the Core and add our listener
mCore = Factory.instance()
.createCore(basePath + "/.linphonerc", basePath + "/linphonerc", this);
mCore.addListener(mCoreListener);
// Core is ready to be configured
configureCore();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
// If our Service is already running, no need to continue
if (sInstance != null) {
return START_STICKY;
}
// Our Service has been started, we can keep our reference on it
// From now one the Launcher will be able to call onServiceReady()
sInstance = this;
// Core must be started after being created and configured
mCore.start();
// We also MUST call the iterate() method of the Core on a regular basis
TimerTask lTask =
new TimerTask() {
#Override
public void run() {
mHandler.post(
new Runnable() {
#Override
public void run() {
if (mCore != null) {
mCore.iterate();
}
}
});
}
};
mTimer = new Timer("Linphone scheduler");
mTimer.schedule(lTask, 0, 20);
return START_STICKY;
}
#Override
public void onDestroy() {
mCore.removeListener(mCoreListener);
mTimer.cancel();
mCore.stop();
// A stopped Core can be started again
// To ensure resources are freed, we must ensure it will be garbage collected
mCore = null;
// Don't forget to free the singleton as well
sInstance = null;
super.onDestroy();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
// For this sample we will kill the Service at the same time we kill the app
stopSelf();
super.onTaskRemoved(rootIntent);
}
private void configureCore() {
// We will create a directory for user signed certificates if needed
String basePath = getFilesDir().getAbsolutePath();
String userCerts = basePath + "/user-certs";
File f = new File(userCerts);
if (!f.exists()) {
if (!f.mkdir()) {
Log.e(userCerts + " can't be created.");
}
}
mCore.setUserCertificatesPath(userCerts);
}
private void dumpDeviceInformation() {
StringBuilder sb = new StringBuilder();
sb.append("DEVICE=").append(Build.DEVICE).append("\n");
sb.append("MODEL=").append(Build.MODEL).append("\n");
sb.append("MANUFACTURER=").append(Build.MANUFACTURER).append("\n");
sb.append("SDK=").append(Build.VERSION.SDK_INT).append("\n");
sb.append("Supported ABIs=");
for (String abi : Version.getCpuAbis()) {
sb.append(abi).append(", ");
}
sb.append("\n");
Log.i(sb.toString());
}
private void dumpInstalledLinphoneInformation() {
PackageInfo info = null;
try {
info = getPackageManager().getPackageInfo(getPackageName(), 0);
} catch (PackageManager.NameNotFoundException nnfe) {
Log.e(nnfe);
}
if (info != null) {
Log.i(
"[Service] Linphone version is ",
info.versionName + " (" + info.versionCode + ")");
} else {
Log.i("[Service] Linphone version is unknown");
}
}
private void copyIfNotExist(int ressourceId, String target) throws IOException {
File lFileToCopy = new File(target);
if (!lFileToCopy.exists()) {
copyFromPackage(ressourceId, lFileToCopy.getName());
}
}
private void copyFromPackage(int ressourceId, String target) throws IOException {
FileOutputStream lOutputStream = openFileOutput(target, 0);
InputStream lInputStream = getResources().openRawResource(ressourceId);
int readByte;
byte[] buff = new byte[8048];
while ((readByte = lInputStream.read(buff)) != -1) {
lOutputStream.write(buff, 0, readByte);
}
lOutputStream.flush();
lOutputStream.close();
lInputStream.close();
}
}
I hope, that will help somebody, because I spend a lot of time trying to find it!
I used by this library:
https://www.mizu-voip.com/Software/SIPSDK/AndroidSIPSDK.aspx
it is very easy.
also i add button for answer the call:
mysipclient.Accept(mysipclient.GetLine());

Categories

Resources