I'm developing an app which connect to android usb device host. When connecting it to an Sony phone and trying to receive the android.hardware.usb.action.USB_DEVICE_ATTACHED by intent filter or directly in the broadcast receiver I receive the next message on Sony Z3 compact device (Android 5.0.2):
Permission Denial: receiving Intent {
act=android.hardware.usb.action.USB_DEVICE_ATTACHED flg=0x10 (has
extras) } to ProcessRecord{***anId**
**anId:my.app.package/u0anId} (pid=xxxxx, uid=xxxxx)
requires com.sonyericsson.permission.BLACKLISTED_USB_DEVICE due to
sender android (uid 1000)
Do I need to call a specific permission? Send a validation number with the request? Is it the usb device that need to send something special?
Can somebody tell me whats the matter?
Thank you for trying to help.
1st UPDATE
Thank's DDPWNAGE for reply... I'm turning arround with the Permission denial... trying to set
<permission
android:name="com.sonyericsson.permission.BLACKLISTED_USB_DEVICE"
android:protectionLevel="signature" />
but this change nothing. I've set the device_filter
<resources>
<usb-device vendor-id="xxxxx" product-id="xxxx"/>
</resources>
with in the manifest
<permission android:name="my.package.USB_PERMISSION" />
<uses-permission android:name="my.package.USB_PERMISSION" />
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />
I've also trying to set
<permission android:name="my.package.USB_PERMISSION"
android:protectionLevel="signature" />
But I cannot figured out why the device should be in any blacklist of usb
2nd UPDATE
I realized that I also have this message before the Permission Denial :
Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:1340 com.android.server.usb.UsbSettingsManager.blacklistedDeviceAttached:757 com.android.server.usb.UsbHostManager.endUsbDeviceAdded:303 com.android.server.usb.UsbHostManager.monitorUsbHostBus:-2 com.android.server.usb.UsbHostManager.access$000:54
When I look up in the UsbHostManager I didn't see any reason why on standard Android devices it works but on Sony devices I've this waring message. In the class we have these 2 methods which check the blacklisted devices :
private boolean isBlackListed(String deviceName) {
int count = mHostBlacklist.length;
for (int i = 0; i < count; i++) {
if (deviceName.startsWith(mHostBlacklist[i])) {
return true;
}
}
return false;
}
/* returns true if the USB device should not be accessible by applications */
private boolean isBlackListed(int clazz, int subClass, int protocol) {
// blacklist hubs
if (clazz == UsbConstants.USB_CLASS_HUB) return true;
// blacklist HID boot devices (mouse and keyboard)
if (clazz == UsbConstants.USB_CLASS_HID &&
subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) {
return true;
}
return false;
}
My device is not a USB_CLASS_HUB nor a USB_CLASS_HID, so the only things I see is that the device is in mHostBlacklist. But does each constructor have is own host blacklist or is this given by android?
mHostBlacklist = context.getResources().getStringArray(
com.android.internal.R.array.config_usbHostBlacklist);
seems to be from android but is it customizable by contructors? And in this case why did Sony blacklist our usb device?
Somebody from Sony is here to help?
Thank you for your time.
Let me try and dissect that log:
Permission Denial: receiving Intent {
Something's receiving an Intent! What is it?
act=android.hardware.usb.action.USB_DEVICE_ATTACHED flg=0x10 (has extras) }
The action here is android.hardware.usb.action.USB_DEVICE_ATTACHED with flg (flag?) 0x10 (hex for 2), guessing that means it (has extras). Guessing that's the intent the reciever's trying to receive.
to ProcessRecord{***anId**
**anId:my.app.package/u0anID} (pid=xxxxx, uid=xxxxx)
Your app is the receiver of the object... got it.
requires com.sonyericsson.permission.BLACKLISTED_USB_DEVICE due to
sender android (uid 1000)
It seems like here's where your error is. In order to get the USB_DEVICE_ATTACHED event sent to your app, your app needs permission to get it first. Most importantly, it needs the BLACKLISTED_USB_DEVICE permission.
It may also be that your device was "blacklisted", but, why? See if BLACKLISTED_USB_DEVICE is a permission that can be enabled, and try again.
As a further hint: Your crash log begins with Permission Denial.
Related
I'm using addNetworkSuggestions on Android 10 to auto connect to an existing Wifi access point using this doc reference.
I'm using the following code :
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager;
val status = wifiManager.addNetworkSuggestions(suggestionsList);
if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
// do error handling here
}
// Optional (Wait for post connection broadcast to one of your suggestions)val intentFilter = IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (!intent.action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
return;
}
// do post connect processing here
}
};
context.registerReceiver(broadcastReceiver, intentFilter);
I'm using an Android 10 device and I'm getting a notification inviting the user to allow or not the permission:
According to the doc, this is the correct behaviour on Android 10:
On Android 11 (API level 30) and higher, the user sees a dialog if the app is running in the foreground, and a notification if the app is running in the background.
On Android 10 (API level 29), the user sees a notification, regardless of whether the app is running in the foreground or the background.
If the permission is not yet accepted, I want to show some text inviting the user to accept the permission notification. But if the user has already accepted the permission notification, I would hide this text.
The question is: How to detect if the user accepted/rejected the permission in the Android system notification ?
I've tried the following:
I've checked the result of wifiManager.addNetworkSuggestions method but it returns STATUS_NETWORK_SUGGESTIONS_SUCCESS even though the permission was not granted yet.
val status = wifiManager.addNetworkSuggestions(suggestionsList);
if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
// this is not triggered even though the user didn't accept the permission notification
}
ActivityCompat.checkSelfPermission
ActivityCompat.checkSelfPermission(this, Manifest.permission.CHANGE_WIFI_STATE)
But it always returns true
AppOpsManager.unsafeCheckOp
From this issue:
appOpsManager.unsafeCheckOp("android:change_wifi_state", Process.myUid(), applicationContext.packageName) == AppOpsManager.MODE_ALLOWED
It returns true even if the permission was not yet accepted/rejected. But it returns false when the user has rejected the permission.
This works only for the case when the user has refused the Android permission notification.
From Desmond's suggestions I've tried using requestPermissions on Manifest.permission.CHANGE_WIFI_STATE. I correctly receive the PackageManager.PERMISSION_GRANTED value. But I keep getting the notification permission.
I have the following permissions in the manifest:
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
I would like to enable bluetooth with my app without user interaction, the prompt does not appear on my devices - Android 7, 8 & 9, and my friend's Android 10. But it appears in my work colleague's devices (Android 10).
I used the following permissions
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
And used the following Bluetooth Adaptor methods.
bluetoothAdapter.enable();
bluetoothAdapter.disable();
I have no intent ACTION_REQUEST_ENABLE or ACTION_REQUEST_DISABLE in my source code.
Am I missing some permissions or methods?
Or is this an environment problem?
Any advise on how should I handle this would be much appreciated.
Thank you.
bluetoothAdapter.enable() will directly run com.android.settings/.bluetooth.RequestPermissionHelperActivity, and you should listen for ACTION_STATE_CHANGED yourself.
I think use the BluetoothAdapter.ACTION_REQUEST_ENABLE is a better way, which will first run com.android.settings.bluetooth.RequestPermissionActivity and then RequestPermissionHelperActivity. RequestPermissionActivity will listen for ACTION_STATE_CHANGED, while your app only need the result code of Activity.RESULT_OK.
private boolean ensureBluetoothEnabled() {
if(((BluetoothManager) Objects.requireNonNull(getSystemService(Context.BLUETOOTH_SERVICE)))
.getAdapter().isEnabled()) {
return true;
} else {
Intent btIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
btIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, Constants.PACKAGE);
startActivityForResult(btIntent, REQUEST_CODE_BL_OPEN);
return false;
}
}
I have a security system in schools, where my tablets are the consoles for each classroom. I've noticed teachers and admin are not restarting the tablets very often (or ever), which has caused issues. I would like to take the task from the clients and program a weekly reboot or shutdown. I have taken a few steps in the right direction:
I have:
Spoken with the Tablet Provider/Scheme Provider, and they have added my app as a privileged app.
Added a whitelist for (what I think are) all required permissions.
Confirmed the privileges exist.
Code to Check Permissions:
public void getGrantedPermissions(final String appPackage) {
List<String> granted = new ArrayList<String>();
try {
PackageInfo pi = getPackageManager().getPackageInfo(appPackage, PackageManager.GET_PERMISSIONS);
for (int i = 0; i < pi.requestedPermissions.length; i++) {
if ((pi.requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
granted.add(pi.requestedPermissions[i]);
}
}
} catch (Exception e) {}
for(int i = 0; i < granted.size(); i++){
Log.e("Permissions", granted.get(i));
}
}
Below is what the log reported. The green permissions are all that I could get on my personal phone. The yellow permissions are what I was able to get, additionally, from the Tablet provider's whitelist. We can confirm by these permissions that I have a privileged app, as well as the shutdown and reboot permissions.
I was able to find a section of code to shutdown the app, but it seems that I can't quite figure out how to use it. Below is the code I have tried, and the error follows:
Intent intent = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
intent.putExtra("android.intent.extra.KEY_CONFIRM", false);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Error upon running code:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.ACTION_REQUEST_SHUTDOWN flg=0x10000000 (has extras) }
"This exception is thrown when a call to Context#startActivity or one of its variants fails because an Activity can not be found to execute the given Intent."
I am assuming that this may require me to modify my manifist.xml, is that correct? If so, I'm unsure how to do so. I feel that I may have to add an to my main activity, where the call is made. Though, I've tried this and it didn't work, or I wrote the code improperly.
Thank you in advance for any assistance!
Figured this one out. I didn't realize a PowerManager existed, but it does, and it works. My solution below. Also, if you didn't read the full question, my app is a privileged/System app, which gives me the authority to manage power. Normal apps will not be able to do this.
Currently running Android 9.0 (might matter, not sure)
try{
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
powerManager.reboot(null);
} catch (Exception e){
Toast.makeText(this, "Error performing this action", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
After reading through a bunch of stale guides and stackoverflows, I was able to usb adb to install an apk as a system app in /system/priv-app that successfully toggles AirplaneMode in Android oreo:
// method in Activity, called via click listener on a Button
private void setMobileRadioEnabled_Option1(boolean enabled) {
android.content.Context context = this;
int value = enabled ? 0 : 1;
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
Settings.System.putInt(
context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, value);
} else {
Settings.Global.putInt(
context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, value);
}
}
Permissions in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
Standard release build in AndroidStudio with custom signing keys, installed via:
adb root
adb remount
adb push app-release.apk /system/priv-app
adb shell chmod 644 /system/priv-app/app-release.apk
adb reboot
On reboot, the app is installed and I can run it without issue.
I check in the notifications drawer / status bar what things are like to start with:
I then click my Button in the app, and check what happens:
As you can see, airplane mode seems to be successfully enabled based on the status of the airplane mode icon. But wifi and cellular data continue to be connected, and the status bar doesn't replace the text "Android" with "Airplane mode". In this state, if I hop over to chrome, I can clearly load websites I've never visited before. So airplane mode doesn't in fact seem to be actually on.
What am I doing wrong? I expect turning on airplane mode via System.putInt() to have the same effect as tapping the airplane mode tile in the status bar. No exceptions or useful error information spitting to logcat when I execute the code.
Checking this answer it seems that you need to send a broadcast to notify that you changed the airplane mode.
The broadcast should be:
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", < current value of the airplane mode >);
sendBroadcast(intent);
Alternatively to jonathanrz's additional code above, which I believe is closer to canonical, I found that the following worked in place of the Settings.System.putInt() code and did not require sending the intent (or adding the permission(s) necessary to send it), at least on Oreo. I created it by merging a few answers and offhand comments from other posts, particularly an answer sketch hidden in a comment by "Navas pk" on Toggle airplane mode in Android:
private void setMobileRadioEnabled_Option2(boolean enabled) {
try {
final ConnectivityManager mConnectivityManager = (ConnectivityManager) getSystemService(android.content.Context.CONNECTIVITY_SERVICE);
final Class mClass = Class.forName(mConnectivityManager.getClass().getName());
final Method setAirplaneMode = mClass.getDeclaredMethod("setAirplaneMode", Boolean.TYPE);
setAirplaneMode.setAccessible(true);
setAirplaneMode.invoke(mConnectivityManager, !enabled);
} catch (Exception e) {
e.printStackTrace();
}
}
I am developing an application with NFC and wifi direct. I get the MAC address using NFC and the Wifi Direct to transfer data. I call discoverpeers() and could get success. But there is no callback WIFI_P2P_PEERS_CHANGED_ACTION, the callback comes only when I go to settings and the select wifidirect.
This was discussed in the other question
Can I turn on WiFi-Direct from code? on Android API-14 (ICS)
"I'd like to add that WiFi direct on JB and above (at least on AOSP) is not active all the time - it only appears to be. If you look at listeners for WiFi direct, it turns itself off after some time. It turns itself back on if you open the wifi direct menu, however. You might have to have the host do a peer search or initialize itself in order to be able to be found. Likely a battery saving trick. I have also found that it's blocking, since as it accepts a connection, the entire system will lock up and fail to connect sometimes. (The system invitation) – Mgamerz "
Can anyone suggest the solution for the problem WIFI_P2P_PEERS_CHANGED_ACTION callback is not got and can get only when manually go to settings->wifi->tap on wifidirect
I used two devices Samsung galaxy nexus and nexus 7 both running on 4.2.2
There is no available API to enable wifiP2P but you can invoke method "enableP2p" from android settings 4.0.1
WifiP2pManager manager = (WifiP2pManager) getActivity().getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(getActivity(), getActivity().getMainLooper(), null);
try {
Method method1 = manager.getClass().getMethod("enableP2p", Channel.class);
method1.invoke(manager, channel);
//Toast.makeText(getActivity(), "method found",
// Toast.LENGTH_SHORT).show();
} catch (Exception e) {
//Toast.makeText(getActivity(), "method did not found",
// Toast.LENGTH_SHORT).show();
}
To disable wifiP2P use this method
Method method1 = manager.getClass().getMethod("disableP2p", Channel.class);
Not from code. The user has to. That's why the demo has the link to wifi settings in the action bar.
When you call manager.discoverPeers(channel, new WifiP2pManager.ActionListener()
define onFailure and look at the reasonCode. If it's 0, then either the Wifi or WiFi direct is off.
If you look at the WiFi Direct demo app, the WifiDirectBroadcast Reciever, this piece of code looks at whether p2p is enabled specifically
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// UI update to indicate wifi p2p status.
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
// Wifi Direct mode is enabled
activity.setIsWifiP2pEnabled(true);
} else {
activity.setIsWifiP2pEnabled(false);
activity.resetData();
}
Then when discover peers is called it looks at the variable set by setIsWifiP2pEnabled
thanks user3093354. to continue with your solution, in order to disable the p2p you have to invoke:
Method method1 = manager.getClass().getMethod("disableP2p", Channel.class);
//Try this it may be help you
WifiManager wifiManager = (WifiManager)this.getSystemService(this.WIFI_SERVICE);
wifiManager.setWifiEnabled(true); //True - to enable WIFI connectivity .
//False -disable WIFI connectivity.
//add this permissions in Manifest file :
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
You can load the wifi driver from a command prompt with the desired concurrency level if you are rooted:
/system/bin/insmod /system/lib/modules/wlan.ko con_mode=3
These are the values:
typedef enum
{
VOS_STA_MODE=0,
VOS_STA_SAP_MODE=1,
VOS_P2P_CLIENT_MODE,
VOS_P2P_GO_MODE,
VOS_MONITOR_MODE,
VOS_FTM_MODE = 5,
VOS_IBSS_MODE,
VOS_P2P_DEVICE_MODE,
VOS_MAX_NO_OF_MODE
} tVOS_CON_MODE;
This is for an Atheros card.