So as the subject states I need to be able to answer a phone call programmatically in Android 4.0.3 on an HTC OneX. I have read several places that the MODIFY_PHONE_STATE permission has been revoked by Google so to do this task you need a work around.
I have looked into two avenues so far:
(1) Following Guy's post here and using a BroadcastReceiver
(2) Using the following code to try and hit a key event through a shell command.
final Runtime r = Runtime.getRuntime();
try {
Process process = r.exec("input keyevent 5");
InputStream stream = process.getErrorStream();
log.v("Process Error Stream: " +stream.toString());
log.v("Sending shell command to Answer Call");
} catch (Exception e) {
log.v("Stack Trace: " + e.getStackTrace().toString());
e.printStackTrace();
}
I use this because keyevent 5 is KeyEvent.CALL according to Google and it works in adb using
adb shell input keyevent 5
My question is, what am I doing wrong? Because logically both of these methods makes sense but neither are working or even generating runtime errors of any kind.
Cheers
After days of research, I found that using both a broadcast receiver route and a runtime.exec() route it is simply not possible to answer a phone call in Android 4.0.3 using the Android API.
For those of you still wondering, I did find some useful information...You CAN answer a call through adb using the command adb shell input keyevent 5 5 is the key code for the call button and in Android it is the KEYEVENT_CALL
This works from Android 2.2 to 4.0 and now after adding the try catch to the last line it works for 4.1.2 and 4.2 Frankly speaking dont know how it works but it works for me.
Log.d(tag, "InSecond Method Ans Call");
// froyo and beyond trigger on buttonUp instead of buttonDown
Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON);
buttonUp.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED");
Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG);
headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
headSetUnPluggedintent.putExtra("state", 0);
headSetUnPluggedintent.putExtra("name", "Headset");
try {
sendOrderedBroadcast(headSetUnPluggedintent, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This is working for me in Android 4.1.2 as well as i have tested on 4.2
This still gives an exception which is handled.
Here are several useful links, check them:
Answer automatically to Incoming Call
How to auto answer call programmatically
Auto answer
Related
I am writing an App that is designed to run on one specific device model (an Android set-top device that runs Amlogic based firmware). I have both root capability and my App is signed with the firmware certificate.
My App is the main focus of the device, and it would be helpful to be able to initiate a complete power-off.
I do not have the shutdown command. I do have the reboot command.
reboot -p does not help. It simply freezes the device while remaining powered on.
The PowerManager is one step better, but it sets the device into sleep mode, instead of a complete shutdown:
PowerManager pm = (PowerManager)getSystemService(Service.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());
I am open to all suggestions - hacky or otherwise. The version of Android is expected to remain at 4.2.2.
Intents
This command will cause the device to reboot. Intent.ACTION_SHUTDOWN does not appear to do anything. Is this Intent perhaps only to report a shutdown, and not to initiate one?
Intent i = new Intent(Intent.ACTION_REBOOT);
i.putExtra("nowait", 1);
i.putExtra("interval", 1);
i.putExtra("window", 0);
sendBroadcast(i);
The most luck I had with this was to request a shutdown by Intent:
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", true);
startActivity(i);
Shutdown Thread
That is a bit closer. Definitely interesting. Can you find an example of using it?
So far I have come up with this:
Class<?> sdClass = Class.forName("com.android.server.power.ShutdownThread");
Constructor<?> con = sdClass.getDeclaredConstructors()[0];
con.setAccessible(true);
for (Method m : sdClass.getDeclaredMethods()) {
if (m.getName().matches("shutdown")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
} else if (m.getName().matches("rebootOrShutdown")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
} else if (m.getName().matches("beginShutdownSequence")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
}
}
shutdown and beginShutdownSequence create NullPointerExceptions (do you see why?) and rebootOrShutdown creates an InvocationTargetException due to an UnsatisfiedLinkError... It cannot find a native method:
java.lang.UnsatisfiedLinkError: Native method not found:
com.android.server.power.PowerManagerService.nativeShutdown:()V at
com.android.server.power.PowerManagerService.nativeShutdown(Native
Method) at
com.android.server.power.PowerManagerService.lowLevelShutdown(PowerManagerService.java:2163)
at
com.android.server.power.ShutdownThread.rebootOrShutdown(ShutdownThread.java:543)
at
com.android.server.power.ShutdownThread.run(ShutdownThread.java:393)
lowLevelShutdown is the function that all the functions eventually reach, when configured to shutdown (and not reboot). So figuring out how to avoid this link error may be key.
In my case, I do not think it is possible to shut the device down how I would like to.
The closest that I managed to get to my target was using:
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", true);
startActivity(i);
That brings up a dialog to turn the device off. This is the perfect solution, but in my case, using it causes the device to crash. It may be that my device is somewhat special, and other devices will not have these restrictions.
In any case, I hope that my testing will help others in their quest.
It work for me on rooted device.
If your device is rooted then you can use below approach
Shutdown:
try {
Process proc = Runtime.getRuntime()
.exec(new String[]{ "su", "-c", "reboot -p" });
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
Restart:
Same code, just use "reboot" instead of "reboot -p".
Runtime.getRuntime().exec(new String[]{ "su", "-c", "reboot -p" });
it works, just with rooted devices!!
To use this code, you need Super User! Works on 4.0 and above!
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", false);
i.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
and put this permission on manifest:
<uses-permission android:name="android.permission.SHUTDOWN" />
An update: for newer Android version, in my case is Android 8.1, they changed the action name. See below:
Intent i = new Intent("com.android.internal.intent.action.REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", false);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Good luck!
In newer android versions you aren't allowed to shut down the device from the nonSystem app.
I am developing an Android-App with "Aide".Aide is an app for developing android apps with android devices. When i start the app, i have created, i get an error like "the app has aborted unfortunately". how can i resolve what happened wrong ? is there a log-file where i can see the stack trace ? is ist possible that everytime an error happens a dialog apperas with the stack trace instead of the message "the app has aborted" ? thanks for everybody who can help me.
Greets
Arne
If you want to observe the stack trace, all you need is a LogCat reader, like CatLog, for instance. Note that if your device is Jelly Bean of higher, you'll need root permissions to read the logs.
EDIT:
Further research indicates that there is a LogCat reader built into AIDE. The root permission issue still applies.
I have never used Aide, but the concept will be the same. You need to be able to debug your app on your phone via your IDE. As an example in Eclipse I would connect my phone via usb and in Eclipse it then shows up as an Android Device in AVD. I then run my App in Debug mode on my phone and all your error output will be in Logcat. Otherwise you will have to code debug logic into your app so that it writes it's own logging onto your fs on you phone.
If you have the Android SDK installed (I guess it's the case), then you can use the adb utility to access the log :
adb logcat
This will show you stacktrace in case of error, and many very other useful informations.
You got 3 options:
Upgrade into a stable Pro version to use the working LogCat on AIDE
Use USB debugging as mentioned by apesa
Use following function to log to local file:
public void appendLog(String text)
// https://stackoverflow.com/a/6209739/8800831
{
File logFile = new File("sdcard/log.file");
if (!logFile.exists())
{
try
{
logFile.createNewFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try
{
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(text);
buf.newLine();
buf. flush();
buf.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Use it like this:
try{
// your code goes here
}catch (Exception e){
appendLog(e);
}
You need to add permission for writing_external_storage in Manifest.
I was curious if there is any library to work with the capacitive buttons of Samsung phones??
I mean to light them up when an event occurs, or blink them, stuffs like that...
Thanks,
rohitkg
There is nothing in the Android SDK for this, as there is no assumption that such buttons exist, have backlights, etc. You are welcome to contact device manufacturers to see if they have a documented and supported means of doing this for their specific devices.
Here's a code snippet I grabbed from samsung-moment-notifications.
Process process = null;
DataOutputStream os = null;
try {
// get root
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
// write the command
os.writeBytes("echo 100 > /sys/class/leds/button-backlight/brightness\n");
os.writeBytes("exit\n");
// clear the buffer
os.flush();
Toast.makeText(NotificationLights.this, "Lights are on", Toast.LENGTH_SHORT).show();
// wait for complete
process.waitFor();
// won't catch an error with root, but it has to have an exception catcher to execute
} catch (Exception e) {
Toast.makeText(NotificationLights.this, "Couldn't get SU, are you rooted?", Toast.LENGTH_SHORT).show();
return;
}
1- You must have a rooted device.
2- You must know the location of the script which turns the lights on/off for each device.
/sys/class/leds/button-backlight/brightness is specific to the Samsung Moment.
If you were to try it on another device it wouldn't work.
I have this code in my app
Alarm1 = Settings.System.getString(getContentResolver(),
Settings.System.NEXT_ALARM_FORMATTED);
Its working on htcs,motorolas,but not on galaxy s phones.The application crashes.
Would the following catch the error without crashing the application service?
String Alarm1=null;
try{
Alarm1 = Settings.System.getString(getContentResolver(),
Settings.System.NEXT_ALARM_FORMATTED);
}
catch (Exception e) {
Log.i("Exception", "Exception next alarm not found = " + e);
}
if (TextUtils.isEmpty(Alarm1)) {
//if i am i here either no alarm is set or couldn't read it from the phone
//do something else
}
Unless there is a different code for the galaxy s, and can i find it.How can i make it throw an exception on a phone that works, for testing purposes?Thanks.
I have the same problem on a widget i developed, it seems that on Galaxy S there is no entry on settings.db with ID NEXT_ALARM_FORMATTED, this makes the app crash. Sadly using try/catch it's not enough to solve the issue, widget still crashes.
I don't have a Galaxy S to debug the issue, if you find any workaround (other than inserting using sqlite3 the row con settings.db) let me know. Maybe you can try to simulate this behaviour by passing an invalid ID to the Settings function, i will try later today...
P.S. To temporary fix this on galaxy s you can (via adb shell)
sqlite3 /data/data/com.android.providers.settings/databases/settings.db
UPDATE "system" SET value='' WHERE name='next_alarm_formatted';
Settings.System.NEXT_ALARM_FORMATTED is deprecated since API 21. Use the following instead:
AlarmManager.AlarmClockInfo alarmInfo = am.getNextAlarmClock();
where am is an instance of AlarmManager.
on Android phones, under Call -> Additional settings -> Caller ID
it is possible to hide your caller ID. I want to do that programatically from my code, but was not able to find a way to do that.
I searched through
android.provider
android.telephony
for 2.1 release and was not able to find it.
Has anybody successfully solved this issue?
Thanks in advance. Best regards.
Here I will describe two approaches I tried.
1.) It is possible to display Additional Call Settings screen from your application. Although it looks like it is part of the Settings application, that is not true. This Activity is part of the Native Phone Application, and it may be approached with the following intent:
Intent additionalCallSettingsIntent = new Intent("android.intent.action.MAIN");
ComponentName distantActivity = new ComponentName("com.android.phone", "com.android.phone.GsmUmtsAdditionalCallOptions");
additionalCallSettingsIntent.setComponent(distantActivity);
startActivity(additionalCallSettingsIntent);
Then user has to manually press on the CallerID preference and gets radio button with 3 options.
This was not actually what I wanted to achieve when I asked this question. I wanted to avoid step where user has to select any further options.
2.) When approach described under 1.) is executed in the Native Phone Application, function setOutgoingCallerIdDisplay() from com.android.internal.telephony.Phone has been used.
This was the basis for the next approach: use Java Reflection on this class and try to invoke the function with appropriate parameters:
try
{
Class <?> phoneFactoryClass = Class.forName("com.android.internal.telephony.PhoneFactory");
try
{
Method getDefaultPhoneMethod = phoneFactoryClass.getDeclaredMethod("getDefaultPhone");
Method makeDefaultPhoneMethod = phoneFactoryClass.getMethod("makeDefaultPhone" , Context.class);
try
{
makeDefaultPhoneMethod.invoke(null, this);
Object defaultPhone = getDefaultPhoneMethod.invoke(null);
Class <?> phoneInterface = Class.forName("com.android.internal.telephony.Phone");
Method getPhoneServiceMethod = phoneInterface.getMethod("setOutgoingCallerIdDisplay", int.class, Message.class);
getPhoneServiceMethod.invoke(defaultPhone, 1, null);
}
catch (InvocationTargetException ex)
{
ex.printStackTrace();
}
catch (IllegalAccessException ex)
{
ex.printStackTrace();
}
}
catch (NoSuchMethodException ex)
{
ex.printStackTrace();
}
}
catch (ClassNotFoundException ex)
{
ex.printStackTrace();
}
Firstly I tried just to use getDefaultPhone(), but I get RuntimeException
"PhoneFactory.getDefaultPhone must be called from Looper thread"
Obviously, issue lies in the fact that I tried to call this method from the Message Loop that was not the Native Phone App one.
Tried to avoid this by making own default phone, but this was a security violation:
ERROR/AndroidRuntime(2338): java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.provider.Telephony.SPN_STRINGS_UPDATED from pid=2338, uid=10048
The only way to overcome (both of) this would be to sign your app with the same key as the core systems app, as described under
Run secure API calls as root, android
I'm not sure if this is a global feature, but Australian phones can hide their number by prefixing the caller's number with #31# or 1831. This may not be the perfect solution, but a prefix like this could possibly work for your requirements during coding.