I am trying to code an app that calls a method in android StatusBarManager. I did it the same way as the hack to expand the android status bar:
try {
Object service = getSystemService("statusbar");
Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
Method expand = statusbarManager.getMethod("disable", new Class[] { int.class });
expand.invoke(service, 0x00200000);
} catch (Exception e) {
e.printStackTrace();
System.out.println("DISABLE HOME ERROR");
}
Except the method I want to call is disable() instead of expand().
However, I am getting a security exception "neither and user nor the current process has permission android.permission.STATUS_BAR.
I tried adding it to the manifest but because it is a system apps permission, it only works if I copy my app to /system/app.
I messed around with RootTools http://code.google.com/p/roottools/ but couldn't figure out how to set the permissions. I tried setPermissions(0) and setUserPermissions("android.permissions.status_bar") but none works. I am not really sure how to use this library.
Any help would be greatly appreciated!
Related
I cannot understand what is the bindServiceAsUser() method used for. Can anyone please kindly explain about it ? Googling seems doesn't help much.
public boolean bindService(Intent intent, ServiceConnection connection, int flags) {
return mContext.bindServiceAsUser(intent, connection, flags, UserHandle.OWNER);
}
I've never felt the need to use bindServiceAsUser(), but here's what the Android documentation has to say about it:
Same as bindService(android.content.Intent,android.content.ServiceConnection,int), but with an explicit userHandle argument for use by system server and other multi-user aware code.
The multi-user support was added in Android 4.2 (API: 17), read about it HERE. In my understanding it'll be mostly used by device manufacturers, releasing special devices for the Enterprise world for example. The best doc for multi-users I've found is THIS one, along with all referenced links there.
As Vesko said, in most android devices multi user is disabled. Some device manufacturers enable it. Foe example you have to bind a service with AIDl and disable a feature for a user in your privileged app. Here you need to know bind service as which user. We can invoke bindServiceAsUser using reflection.
UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
UserHandle owner = null;
owner = um.getUserForSerialNumber(0L);
try {
MethodUtils.invokeMethod(getApplicationContext(), "bindServiceAsUser", new Object[]{i, serviceConnection, Context.BIND_AUTO_CREATE, owner});
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
I am able to turn on/off Bluetooth without any prompt using the following code. It requires BLUETOOTH and BLUETOOTH_ADMIN permissions.
boolean isEnabled = bluetoothAdapter.isEnabled();
if (enable && !isEnabled) {
return bluetoothAdapter.enable();
} else if (!enable && isEnabled) {
return bluetoothAdapter.disable();
}
But didn't find any way to set Bluetooth discoverable without user prompt. It's wired to prompt every time to user. There is no "don't ask me again" feature I afraid. Is there any good way to make Bluetooth device discoverable? I don't care about the duration. Also my device is not rooted.
More Info
I found source code of BluetoothAdapter.java and it has a public method named setDiscoverableDuration. But why I can't access it? Why some public methods are hidden in Api documentations? How did they even do that? all methods are public.
Finally I have found a way to do this using reflection.
Method method;
try {
method = bluetoothAdapter.getClass().getMethod("setScanMode", int.class, int.class);
method.invoke(bluetoothAdapter,BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,120);
Log.e("invoke","method invoke successfully");
}
catch (Exception e){
e.printStackTrace();
}
Warning: Above method is trying to invoke hidden method. So in future maybe it will not work.
I am working on an android that will allow the user to add numbers to a blacklist. When an incoming number matches a number in the blacklist then the call should be rejected, even if the phone does ring briefly and then disconnects the call.
Everything I've found including on SO, says it can't be done without creating AIDL in com.android.internal.telephony which I've created but I can't add the modify phone state permission as it says it needs to be a system app.
I am targetting ICS upwards and I have seen other apps block calls in ICS and up so how is this done. I've also tried adding the modify phone state permission to the manifest file and it displays an error saying that it is only available for system apps so how do I get around this issue. I don't want the app to have to be rooted.
Thanks for any help you can provide
I've found the answer by a bit of luck.
Instead of adding permission MODIFY_PHONE_STATE add permission CALL_PHONE
Create a new package called com.android.internal.telephony
Inside this package create a file called ITelephony.aidl and add the following content
package com.android.internal.telephony;
interface ITelephony {
boolean endCall();
void answerRingingCall();
void silenceRinger();
}
Use the below code in order to block the call
try
{
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
com.android.internal.telephony.ITelephony telephonyService = (ITelephony)m.invoke(tm);
//telephonyService.silenceRinger();
telephonyService.endCall();
}
catch (Exception e)
{
Log.d("BLOCK CALL", e.toString());
Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();
}
Hope this helps others, its not too easy to find. I don't understand why Google removed the ability to do this without mucking about like this though.
I'm writing an Android app which receives information from a Bluetooth device. Our client has suggested that the Bluetooth device (which they produce) will change its name depending on certain conditions - for the simplest example its name will sometimes be "xxx-ON" and sometimes "xxx-OFF". My app is just supposed to seek this BT transmitter (I use BluetoothAdapter.startDiscovery() ) and do different things depending on the name it finds. I am NOT pairing with the Bluetooth device (though I suppose it might be possible, the app is supposed to eventually work with multiple Android devices and multiple BT transmitters so I'm not sure it would be a good idea).
My code works fine to detect BT devices and find their names. Also, if the device goes off, I can detect the next time I seek, that it is not there. But it seems that if it is there and it changes name, I pick up the old name - presumably it is cached somewhere. Even if the bluetooth device goes off, and we notice that, the next time I detect it, I still see the old name.
I found this issue in Google Code: here but it was unclear to me even how to use the workaround given ("try to connect"). Has anyone done this and had any luck? Can you share code?
Is there a simple way to just delete the cached names and search again so I always find the newest names? Even a non-simple way would be good (I am writing for a rooted device).
Thanks
I would suggest 'fetchUuidsWithSdp()'. It's significance is that, unlike the similar getUuids() method, fetchUuidsWithSdp causes the device to update cached information about the remote device. And I believe this includes the remote name as well as the SPD.
Note that both the methods I mentioned are hidden prior to 4.0.3, so your code would look l ike this:
public static void startServiceDiscovery( BluetoothDevice device ) {
// Need to use reflection prior to API 15
Class cl = null;
try {
cl = Class.forName("android.bluetooth.BluetoothDevice");
} catch( ClassNotFoundException exc ) {
Log.e(CTAG, "android.bluetooth.BluetoothDevice not found." );
}
if (null != cl) {
Class[] param = {};
Method method = null;
try {
method = cl.getMethod("fetchUuidsWithSdp", param);
} catch( NoSuchMethodException exc ) {
Log.e(CTAG, "fetchUuidsWithSdp not found." );
}
if (null != method) {
Object[] args = {};
try {
method.invoke(device, args);
} catch (Exception exc) {
Log.e(CTAG, "Failed to invoke fetchUuidsWithSdp method." );
}
}
}
}
You'll then need to listen for the BluetoothDevice.ACTION_NAME_CHANGED intent, and extract BluetoothDevice.EXTRA_NAME from it.
Let me know if that helps.
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.