From my mobile device(scanner) I am trying to write to a descriptor in a connected wearable(broadcaster).
on the wearable, I have defined the descriptor as
readCharacteristic = new BluetoothGattCharacteristic(Constants.READ_CHAR_UUID,
BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ);
readCharacteristic.addDescriptor(new BluetoothGattDescriptor(Constants.NOTIFY_DESC_UUID,
BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE));
on the mobile, I try to write to the characteristic with
BluetoothGattDescriptor descriptor = readCharacteristic.getDescriptor(Constants.NOTIFY_DESC_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
Unfortunately, this fails with status GATT_WRITE_NOT_PERMITTED in
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
}
In the wearable logcat I see gatts_write_attr_perm_check - GATT_WRITE_NOT_PERMIT.
The same thing happens when I try to write to a characteristic.
What is weird is that the write succeeds when using an iOS scanner. This means that the wearable part is correct.
I have the permissions in the Manifest:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Devices used:
Nexus 5x 6.0.1 API 23,
Moto 360 5.1.1 API 22
Does anyone have an idea how to fix this descriptor/characteristic write issue?
From my mobile device(scanner) I am trying to write to a descriptor in
a connected wearable(broadcaster).
In this case it should be mobile device(central) and connected wearable(peripheral). scanner and broadcaster does not establish BLE connection actually.
Regarding to the write failure, it was reject at the function gatts_write_attr_perm_check when application try to write data to database. the code just like below:
else if (!(perm & GATT_WRITE_ALLOWED))
{
status = GATT_WRITE_NOT_PERMIT;
GATT_TRACE_ERROR( "gatts_write_attr_perm_check -GATT_WRITE_NOT_PERMIT");
}
So, the problem is the recorded perm was not eligible with GATT_WRITE_ALLOWED, which is
> (GATT_PERM_WRITE | GATT_PERM_WRITE_ENCRYPTED |\
> GATT_PERM_WRITE_ENC_MITM | GATT_PERM_WRITE_SIGNED |\
> GATT_PERM_WRITE_SIGNED_MITM)
So, could you have a following try:
1) unpair the device and pair the device again.
2) enable the high security level e.g. enable the MITM.
And I assume you want to enable the notification right? I could not get all the code you have but can you also try this(quote from Android website):
private BluetoothGatt mBluetoothGatt;
BluetoothGattCharacteristic characteristic;
boolean enabled;
...
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
...
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
Related
Hello Android developers, I am trying to make my app the default sms app on my phone with the following code but its not working as it is not displaying the dialog for a user to choose which app to use as the default sms app. I am aware that as of Android 10 then we need to use the RoleManager class to check if the app is the default sms app and additionally check if the app holds the role and then start an activity for the user to set the current app to have that role. I have followed every required step from the documentation and some previously posted questions on this site but there seems to be an error that is silent because no exception is thrown. Help me make this code display the dialog to the user for changing the app for the sms roles.
//register a delegate for reading the phone number
button.Click += (o, p) =>
{
Toast.MakeText(this,Telephony.Sms.GetDefaultSmsPackage(ApplicationContext),ToastLength.Long).Show();
//check first if the app is the default sms privilege holder
if (Telephony.Sms.GetDefaultSmsPackage(ApplicationContext) != PackageName)
{
//use the role manager api to change the default sms app
//check the api level
if (Build.VERSION.SdkInt > BuildVersionCodes.P)
{
Log.Debug("API", "api greater than 28");
//api level is greater than 28 then use RoleManager class
RoleManager roleManager = (RoleManager)GetSystemService(Context.RoleService);
//check if the role is available first
if (roleManager.IsRoleAvailable(RoleManager.RoleSms))
{
//log the role manager availability
Log.Debug("Sms role available", roleManager.IsRoleAvailable(RoleManager.RoleSms).ToString());
//chek if the role is held
if (roleManager.IsRoleHeld(RoleManager.RoleSms))
{
//means the app has the sms role and we do not need to change
}
else
{
Log.Debug("Info", "Sms Role is not held");
//means the app does not have the sms role and we need to request the user to change
Intent changeIntent = roleManager.CreateRequestRoleIntent(RoleManager.RoleSms);
StartActivityForResult(changeIntent,909);
}
}
else
{
//the role is not avaialble and cannot be changed
Log.Debug("Sms role available",
roleManager.IsRoleAvailable(RoleManager.RoleSms).ToString());
}
}
else
{
//api level is less than or equal to 28 use the deprecated way
Intent changeIntent = new Intent(Telephony.Sms.Intents.ActionChangeDefault);
changeIntent.PutExtra(Telephony.Sms.Intents.ExtraPackageName, PackageName);
StartActivity(changeIntent);
}
}
and here is my manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="SimCardManager.SimCardManager">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE"/>
<uses-permission android:name="android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER"/>
<application android:allowBackup="true" android:label="#string/app_name" android:supportsRtl="true" android:theme="#style/AppTheme">
</application>
</manifest>
An answer in Android Java is also accepted as that is what I use to convert Java code to C#, the code is still Android Java working as a Xamarin Android C# binding, Thank You for your time and effort helping me.
When attempting to create a temp file on Android 10 I am getting a permission denied error. Could someone please write a tutorial on how to create one in the external storage? Most are outdated and not for current versions of Android
Here is the logcat
2020-02-22 13:46:43.766 9544-9544/com.myapp.test E/MainActivity: Image file creation failed
java.io.IOException: Permission denied
at java.io.UnixFileSystem.createFileExclusively0(Native Method)
at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:317)
at java.io.File.createTempFile(File.java:2018)
at com.myapp.test.MainActivity.create_image(MainActivity.java:915)
at com.myapp.test.MainActivity.access$200(MainActivity.java:85)
at com.myapp.test.MainActivity$6.onShowFileChooser(MainActivity.java:513)
at vo.runFileChooser(PG:10)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:336)
at android.os.Looper.loop(Looper.java:197)
at android.app.ActivityThread.main(ActivityThread.java:7762)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1047)
My AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:remove="android:maxSdkVersion" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE" />
And code in the MainActivity.Java
private File create_image() throws IOException {
#SuppressLint("SimpleDateFormat")
String file_name = new SimpleDateFormat("yyyy_mm_ss").format(new Date());
String new_name = "file_"+file_name+"_";
File sd_directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return File.createTempFile(new_name, ".jpg", sd_directory); // fails due to permission denied
}
I was using official documentation to implement taking a photo from camera:
https://developer.android.com/training/camera/photobasics
yet it doesn't work and throws an exception on createTempFile method. Strangely google hasn't updated the code.
Here's a solution I've found:
Add:
android:requestLegacyExternalStorage="true"
to AndroidManifest.xml. No need to change anything in code. Works for now, but may not in upcoming Android versions.
You need to change
File sd_directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
to
File sd_directory = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
You need to add a file provider
https://developer.android.com/reference/android/support/v4/content/FileProvider
And request the read/write storage permissions at runtime.
https://developer.android.com/training/permissions/requesting
In android 10 permission isn't directly accepted. So, you have ask from user to accept permission. There's a library which you can use for asking permission. Let me add that link
It is known as Dexter Library
You have to add a line to gradle.build
implementation 'com.karumi:dexter:6.2.2'
Following source code used for single permission at a time.
Dexter.withContext(this)
.withPermission(Manifest.permission.CAMERA)
.withListener(new PermissionListener() {
#Override public void onPermissionGranted(PermissionGrantedResponse response) {/* ... */}
#Override public void onPermissionDenied(PermissionDeniedResponse response) {/* ... */}
#Override public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {/* ... */}
}).check();
There's way to asking for multiple permission in Dexter library. You can get that on that link
As you are using getExternalStoragePublicDirectory In android 10+, you can't write on public folder directly. One way is to use getExternalFilesDir to capture image and then use MediaStore APIs to copy file into public directory.
I want to use this code in order to reboot my RPI3 running Android Things:
public static void Reboot()
{
try {
Process proc = Runtime.getRuntime().exec(new String[]{"su", "-c", "reboot"});
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
}
I get the following error:
java.io.IOException: Cannot run program "su": error=13, Permission denied
I add to the manifest all the permission
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.SET_TIME_ZONE"/>
<uses-permission android:name="android.permission.SHUTDOWN"/>
Am I missing something?
/system/bin/reboot binary in DP 4, so as in all the previous dev previews, has world-executable permission, i.e. the following yields
adb shell ls -l /system/bin | grep reboot
-rwxr-xr-x 1 root shell ... reboot
That said, it is yet possible to execute the binary for any user (a.k.a app process in Android) without a need to grab su. Just execute in Java for
rebooting
Runtime.getRuntime().exec("reboot");
or for powering off
Runtime.getRuntime().exec("reboot -p");
No permission's needed in AndroidManifest.xml to run the binary successfully.
Caution: in case of security model changes in newer OS versions this approach may not work.
You can now do a reboot using:
https://developer.android.com/things/reference/com/google/android/things/devicemanagement/DeviceManager.html
Example
public class SomeActivity extends Activity {
void doReboot() {
DeviceManager.getInstance().reboot();
}
void doFactoryReset() {
boolean wipeExternalCard = true;
DeviceManager.getInstance().factoryReset(wipeExternalCard);
}
}
You need the com.google.android.things.permission.REBOOT permission
Access to system-protected features (such as those provided by the PowerManager.reboot() API) will be available to apps running on Android Things in a future developer preview release. You cannot (and should not) attempt to run your app process as the root user via su.
As a side note, the developer images for Android Things are built as userdebug, which means you can access root from the shell by simply rebooting the ADB daemon with the adb root command before you attempt to access the shell. This gives you any root access you may need during development without compromising the device security and allowing app processes to run as root.
You need a root access.
public static void runCmd(String cmd) {
DataOutputStream os;
try {
Process process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(cmd + "\n");
os.writeBytes("exit\n");
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Then you can run any commands that require root access like this: runCmd("reboot");
After doing tons of research on the topic, I learned that my app may not show up for tablets in the Play Store if I have some permissions that the tablet cannot handle. Here are my current permissions:
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIBRATE" android:permission ="false" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.INTERNET" />
Will any of these permissions cause the app to not show up in the play store?
Some tablets may not be able to handle the <uses-permission android:name="android.permission.READ_PHONE_STATE" /> because don't get calls...So, I need to do something in my java code saying:
if(Device has the ability to get calls){ //Execute code}
So, since the telephone thing is optional, I changed it's permission to:
<uses-feature android:name="android.permission.READ_PHONE_STATE" android:required="false"/>
How do I get that? If you need it, this is where I am actually checking if the user is getting a call, I use it to mute my application:
private PhoneStateListener phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_RINGING) {
onPhoneCallInterrupt(); //Method I created that just mutes the audio
} else if (state == TelephonyManager.CALL_STATE_IDLE) {
} else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
onPhoneCallInterrupt(); //Method I created that just mutes the audio
}
}
};
So, what do I do to handle the exception that may occur if a tablet is using the app, like this?
if(Device has the ability to get calls){ //Execute code}
Thanks,
Ruchir
TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE); //gets the current TelephonyManager
if (tm.getSimState() != TelephonyManager.SIM_STATE_ABSENT){
//the device has a sim card
} else {
//no sim card available
}
Check more here
Keep your phone state permission on an if-else block. When user will try to access that feature or you might need to check phone state, throw a dialog box on the screen. This link shows how to ask for user's permission.
From API 23, User's will need to explicitly permit each and every permission so, it is a good thing if you do that for all.
Beside, upon users permission, the manifest file will be overwritten so, you won't have to worry about that either.
Does it solve ur issue?
Hí,
I have an java application that makes use bluetooth to search for devices. When the user presses the native Bluetooth button to turn it off my application shows the bluetooth status offline. When the user presses the native Bluetooth button to turn it on, my application should go back to work but it does not. For my scan back to work I need to close and open my application.
How to fix this programmatically ?
Make sure you have the following permissions in your manifest:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
You can enable bluetooth by using the following in an Activity or Service class:
BluetoothAdapter.getDefaultAdapter().enable();
If you are trying to listen for when Bluetooth is enabled, register a BroadcastReceiver listening for the BluetoothAdapter.ACTION_STATE_CHANGED action:
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
if (state == BluetoothAdapter.STATE_OFF) {
// Bluetooth is turned off
} else if (state == BluetoothAdapter.STATE_ON) {
// Do your scan
}