Simple kotlin app under android studio that makes a loadURL to a local address:-
The function often fails, probably due to local net latency with:
Web Page not available
The web page at http://192.168.1.144/apikey/webcam could not be loaded because:
net: ERR_ADDRESS_UNREACHABLE
I have
android:usesCleartextTraffic="true"
<uses-permission android:name="android.permission.INTERNET"/>
in the manifest, and the loadurl often is fine
In order to capture the error and provide a message an
onReceivedError()
action is used.
It never fires
Is the syntax of the onReceivedError correct? It refers to WebView rather than my instance myWebview (which causes a reference error), and I've moved the scope around to no effect.
The Android Studio comment says that the function is never used. A big hint, but I can't see which scope to place it in.
Or is this type of error one of those not caught by OnReceivedError. If so, how which function would?
Ideally I'd like to increase the 'wait' time of the LoadUrl function so that the lazy local IP can respond.
I've copied this from other examples.
I'd really welcome some help please
Here is my class code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create the NotificationChannel
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val CHANNEL_ID = "only_channel"
val mChannel = NotificationChannel(CHANNEL_ID, name, importance)
mChannel.description = descriptionText
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create channel to show notifications.
val channelId = getString(R.string.default_notification_channel_id)
val channelName = getString(R.string.default_notification_channel_name)
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager?.createNotificationChannel(NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_HIGH))
}
val myWebView: WebView = findViewById(R.id.webview)
/*myWebView.loadUrl("https://amazon.co.uk")*/
myWebView.webViewClient = WebViewClient()
myWebView.setWebViewClient(object : WebViewClient() {
fun onReceivedError(view: WebView , errorCode: Int, description: String, failingUrl: String, getContext: Context) {
Log.i("WEB_VIEW_TEST", "error code:$errorCode")
Toast.makeText(getContext, "Webcam not reachable",Toast.LENGTH_SHORT ).show()
}
})
WebView.setWebContentsDebuggingEnabled(true)
/*5 March 2021*/
myWebView.clearCache(true)
myWebView.loadUrl("http://192.168.1.144/apikey/webcam")
val disable_button: Button = findViewById(R.id.disable)
disable_button.setOnClickListener {
myWebView.loadUrl("http://192.168.1.144/apikey/disable")
}
fun onReceivedError(
view: WebView,
request: WebResourceRequest,
error: WebResourceError
) {
Toast.makeText(this, "Webcam not reachable", Toast.LENGTH_SHORT).show()
}
}
}
I am getting errors on my toast message with the following:
// JS FUNCTIONS FOR THE WEBVIEW
private fun loadJs(webView: WebView) {
webView.loadUrl(
"""javascript:(function f() {
var btns = document.getElementsByTagName('button');
for (var i = 0, n = btns.length; i < n; i++) {
if (btns[i].getAttribute('id') === 'testBTN') {
btns[i].setAttribute('onclick', 'Android.onClicked()');
}
}
})()
"""
)
}
// KOTLIN FUNCTIONS THAT JS CAN CALL
object AndroidJSInterface {
#JavascriptInterface
fun onClicked() {
Utils.showToast("in the js")
Log.i("MK", "JS BUTTON CLICKED")
}
}
/*
* ##############################################################################################
*/
object Utils {
fun showToast(msg: String?, ctx: Context = MainActivity().applicationContext) {
Toast.makeText(ctx, msg, Toast.LENGTH_SHORT).show()
}
}
The above codes listen to button clicks of my webview, the Log.i do give me results when I press my targeted button. The toast gives me an error.
W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
What is the best method to call the applicationContext in this manner?
I am coding this in Android Studio Kotlin
Thank you in advance for your assistance.
I've added <uses-permission android:name="android.permission.BLUETOOTH" /> to my manifest but the error
Missing permission required by BluetoothAdapter.isEnabled: android.permission.BLUETOOTH.
is still there.
Also, in ContextCompat.checkSelfPermission(...) what is the first parameter CONTEXT? The documentation https://developer.android.com/training/permissions/requesting does not say.
And am I correct that I need to disconnect and reconnect bluetooth whenever the app is not being used?
class MainActivity : AppCompatActivity() {
var bt: BluetoothAdapter? = null
var bts: BluetoothSocket? = null
val REQUEST_BLUETOOTH_PERMISSION: Int = 1
val REQUEST_BLUETOOTH_ENABLE: Int = 2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))
{
Toast.makeText(
getApplicationContext(),
"Device does not support Bluetooth therefore this application cannot run.",
Toast.LENGTH_SHORT
).show();
return;
}
bt = BluetoothAdapter.getDefaultAdapter()
if (bt == null) {
// This device does not have Bluetooth.
Toast.makeText(
getApplicationContext(),
"Device does not have a Bluetooth adapter therefore this application cannot run.",
Toast.LENGTH_SHORT
).show();
return;
}
bluetoothConnect();
}
fun bluetoothConnect() {
if (ContextCompat.checkSelfPermission(
CONTEXT, // What is this? It's not explained at https://developer.android.com/training/permissions/requesting
Manifest.permission.BLUETOOTH
) == PackageManager.PERMISSION_GRANTED
) {
if (bt.isEnabled == false) { // Error: Missing permission required by BluetoothAdapter.isEnabled: android.permission.BLUETOOTH.
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBtIntent, REQUEST_BLUETOOTH_ENABLE)
} else {
val pairedDevices: Set<BluetoothDevice>? = bt.bondedDevices
pairedDevices?.forEach { device ->
val deviceName = device.name
val deviceHardwareAddress = device.address // MAC address
}
}
}
else {
// Request permission. That will call back to onActivityResult which in the case of success will call this method again.
// Ask for permission.
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.BLUETOOTH),
REQUEST_BLUETOOTH_PERMISSION
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_BLUETOOTH_PERMISSION) {
if (resultCode == RESULT_OK) {
bluetoothConnect();
} else {
Toast.makeText(
getApplicationContext(),
"This application cannot run because it does not have Bluetooth permission.",
Toast.LENGTH_SHORT
).show();
// Do we need to quit? How?
}
}
else if( requestCode == REQUEST_BLUETOOTH_ENABLE)
{
if(resultCode == RESULT_OK)
{
// try again
bluetoothConnect();
}
else {
Toast.makeText(
getApplicationContext(),
"This application cannot run because Bluetooth is not enabled and could not be enabled.",
Toast.LENGTH_SHORT
).show();
// Do we need to quit? How?
}
}
}
override fun onPause() {
super.onPause()
// Release Bluetooth
}
override fun onResume() {
super.onResume()
// Connect Bluetooth
}
override fun onStop() {
super.onStop()
// Release Bluetooth
}
override fun onStart() {
super.onStart()
// Connect Bluetooth
}
}
Edit:
added additional BT check to code,
adding manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rwb.btconnectortest">
<uses-permission android:name="android.permission.BLUETOOTH" />
<!--<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />-->
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/btconnectortestTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Just because comments are not good for this, let me give you a list of things you ought to do before you can act with Bluetooth. (apologies this is in Java because that's what I have right now, but very easy to translate to Kotlin if needed)
I'm doing this for BT LE (low energy) which is the preferred way for.. obvious reasons.
Did you add the permission(s) to the Manifest? You need something like
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
Make sure Bluetooth exists and is turned on...
// Does BLE exist?
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
final BluetoothManager manager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
Now that you have a manager, you need to get the BluetoothAdapter:
BluetoothAdapter bluetoothAdapter = manager.getAdapter();
All this is fine in onCreate, but keep in mind that you have to check if BT is enabled every time the user resumes the activity (For it could have been turned off/disabled/revoked/etc).
Likely in onResume:
// obviously, you need to check that Bt adapter isn't null and all that,
// otherwise you ought to go back and "construct" it again, check permissions, etc.
adapter = getBTAdapter(); // do all the checks in there...
boolean bluetoothEnabled = adapter != null && adapter.isEnabled();
If the BT radio is off (user turning it off), you can programmatically enable it, if you have the corresponding permission (which I think is BT admin or similar, you're gonna have to search on that one, because it's been a while).
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> I believe it was.
Since BT is a radio that needs power, it will take a while (seconds) to turn on and be available. For this you need to "listen" with Yet Another broadcast receiver...
In other words, the activity will fire an intent (startActivityForResult(...)) telling Android to enable BT, you will subscribe to that broadcast to listen to the callback. Once android informs you that BT is on, you can go back to step 1 and start checking if it's enabled, you have permission, etc.
The callback is if I have not forgotten too much... looked like
public void onReceive(Context context, Intent intent) {
In there you ought to check for various BluetoothAdapter states... among them:
BluetoothAdapter.ACTION_STATE_CHANGED
This signals that the state changed, but another nested if is needed to determine to what state...
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE);
switch (state) {
case BluetoothAdapter.STATE_OFF:
case BluetoothAdapter.STATE_TURNING_OFF:
case BluetoothAdapter.STATE_TURNING_ON:
case BluetoothAdapter.STATE_ON:
}
Those are all the ones you care (check the BluetoothAdapter enum for more info).
In the ON you know BT is on... so..
Now you can tell the adapter that you want to scan...
adapter.startLeScan(callback);
(remember to call stopLeScan(callback) when you're done).
As each device is found, the callback will be called with the info you need to attempt to connect and pair (if needed).
The signature of the callback (LeScanCallback) is something like:
public void onScan(final BluetoothDevice device, int rssi, byte[] record);
(I'm typing by memory, so it may be a different name but you get the idea)
This is, as far as I can remember the old API.
API 21 has a ScanSettings.Builder() where you can specify how you want to scan, but it's essentially a similar method. Initiate scan, pass a callback and wait for results to show up.
You have various modes too:
SCAN_MODE_BALANCED: Balance battery efficiency and scan speed
SCAN_MODE_LOW_LATENCY: Prefer scan speed over battery
SCAN_MODE_LOW_POWER: Prefer battery efficiency over scan speed
SCAN_MODE_OPPORTUNISTIC: can't remember :) I think it was to use other scanner results 'around' you. Never used it.
Once you have identified the device you were looking for the BluetoothDevice has everything you need to tell BT to "connect" to it.
public void onScanResult(int callbackType, ScanResult scanResult) {
^ this is the signature of the "new" Scanner.
From that ScanResult, you can do:
int rssi = result.getRssi();
BluetoothDevice device = result.getDevice();
String advertiseName = device.getName();
String macAddress = device.getAddress();
If the scan fails for any reason, you get a callback on onScanFailed(int errorCode).
And again, there are various "reasons" (check the errorCode) why the scan failed.
Remember I may be mixing API 18 or API 21 "apis" here, but the concept is very similar in both.
Once you have finally grabbed a Device's MAC address... you can ask the adapter to try to connect to it:
BluetoothDevice device = adapter.getRemoteDevice(macAddress);
device.connectGatt(context, false, anotherCallback);
The callback is of BluetoothGattCallback and again, it has a bunch of methods among them onConnectionStateChange...
At this point you ought to read more about how Bluetooth works (and how it works on Android) because there are various modes (Gatt being one way) of operating with BT. It's impossible to know each and how/what you want to do once connected.
The rule of thumb will be: make sure you're prepared to having to re-pair or re-request permissions, because it's ultimately the user's choice to disable, turn off, walk-away, revoke permission, etc. at any point during this.
Good luck!
in manifest file add these two permission
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH"
#########################################################
*NOTE:i attached my bluetooth kotlin code , and its work with me. I enter code herehope this helpful
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var myBluetooth:BluetoothAdapter? = null
lateinit var mypairedDevices:Set<BluetoothDevice>
val Request_Enable_Blutooth=1
companion object {
val EXTRA_ADDRESS :String= "Device_Address"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
myBluetooth= BluetoothAdapter.getDefaultAdapter()
if (myBluetooth == null)
{
Toast.makeText(applicationContext, "Bluetooth Device Not Available", Toast.LENGTH_LONG).show()
}
if (!myBluetooth!!.isEnabled)
{
val enableBlutoothIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBlutoothIntent, Request_Enable_Blutooth)
}
binding.BTNPairedDevices.setOnClickListener {
pairedDeviceList()
}
}
private fun pairedDeviceList (){
mypairedDevices = myBluetooth!!.bondedDevices
val list : ArrayList<BluetoothDevice> = ArrayList()
if (!mypairedDevices.isEmpty())
{
for ( device:BluetoothDevice in mypairedDevices)
list.add(device)
//list.add(device.name() + "\n" + device.address())
Log.i("Device", "This is messeage")
}
else {
Toast.makeText(applicationContext, " NO PAIRED DEVICES FOUND", Toast.LENGTH_LONG).show()
}
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, list)
binding.DeviceListView.adapter = adapter
binding.DeviceListView.onItemClickListener = AdapterView.OnItemClickListener{ _, _, position, _ ->
val device: BluetoothDevice = list[position]
val address: String = device.address
val intent = Intent(this, LedController::class.java)
intent.putExtra(EXTRA_ADDRESS, address)
startActivity(intent)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == Request_Enable_Blutooth)
{
if(resultCode ==Activity.RESULT_OK)
{
if (myBluetooth!!.isEnabled)
{ Toast.makeText(applicationContext, "Bluetooth Enabled", Toast.LENGTH_LONG).show()
}
else ( Toast.makeText(applicationContext, "Bluetooth Disabled", Toast.LENGTH_LONG).show()
)
}
} else if(resultCode == Activity.RESULT_CANCELED)
Toast.makeText(applicationContext, "Bluetooth has been canceled", Toast.LENGTH_LONG).show()
}
}
I restarted AndroidStudio and now the error has disappeared. What a complete piece of rubbish.
But now the layout is broken...
This question is specific to a lately strange behavior of the Azure mobile Apps Android sdk. Everything was working fine for weeks. Now, my android client app suddenly can't connect to my web app any more. A Toast says "Error while processing request". In Android Studio debugger, I found the exception inside the SDK file MobileServiceConnection.java.
java.io.IOException: stream was reset: PROTOCOL_ERROR
In Azure Portal, my app shows "Healthy" status, but I can see the HTTP errors. Please help.
Following is my code, which was working fine and now throws error.
// Create the Mobile Service Client instance, using the provided mobile app URL.
try {
mClient = new MobileServiceClient(mMobileBackendUrl, activityContext).withFilter(
new ServiceFilter() {
#Override
public ListenableFuture<ServiceFilterResponse> handleRequest(ServiceFilterRequest request, NextServiceFilterCallback nextServiceFilter) {
// Get the request contents
String url = request.getUrl();
String content = request.getContent();
if (url != null) {
Log.d("Request URL:", url);
}
if (content != null) {
Log.d("Request Content:", content);
}
// Execute the next service filter in the chain
ListenableFuture<ServiceFilterResponse> responseFuture = nextServiceFilter.onNext(request);
Futures.addCallback(responseFuture, new FutureCallback<ServiceFilterResponse>() {
#Override
public void onFailure(Throwable exception) {
Log.d("Exception:", exception.getMessage());
}
#Override
public void onSuccess(ServiceFilterResponse response) {
if (response != null && response.getContent() != null) {
Log.d("Response Content:", response.getContent());
}
}
});
return responseFuture;
}
}
);
setAzureClient(mClient);
}catch(MalformedURLException e){
createAndShowDialog(new Exception("There was an error creating the Mobile Service. Verify the URL"), "Error");
}catch(Exception e){
createAndShowDialog("There was an error creating the Mobile Service. "+ e.toString(), "Error");
}
Toast.makeText(context, context.getString(R.string.online_authentication), Toast.LENGTH_SHORT).show();
authenticate();
}
private void authenticate() { // give access only to authenticated users via Google account authentication
HashMap<String, String> parameters = new HashMap<>();
parameters.put("access_type", "offline");//use "Refresh tokens"
//login with the Google provider. This will create a call to onActivityResult() method inside the context Activity, which will then call the onActivityResult() below.
mClient.login(MobileServiceAuthenticationProvider.Google, url_scheme_of_your_app, GOOGLE_LOGIN_REQUEST_CODE, parameters);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// When request completes
if (requestCode == 1) {
try {
MobileServiceActivityResult result = mClient.onActivityResult(data);
if (result.isLoggedIn()) {
Toast.makeText(context, context.getString(R.string.azure_auth_login_success) /*+ " " + mClient.getCurrentUser().getUserId()*/, Toast.LENGTH_SHORT).show();
mUserId = mClient.getCurrentUser().getUserId();
} else {//>>>>THIS IS WHERE I AM GETTING THE ERROR
String errorMessage = result.getErrorMessage();
Toast.makeText(context, errorMessage, Toast.LENGTH_SHORT).show();// Error While processing request (it comes form the MobileServiceConnection.java file inside sdk)
}
}catch(Exception e){
Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();
}
}
}
I found the answer myself. The error was due to an Azure App Service HTTP2 connection issue. It has nothing to do with the app code. For anyone facing the same problem, here is the solution.
Go to https://resources.azure.com/
Make sure you are in Read/Write mode by clicking in the option to the left of your name.
From the left column, browse to: https://resources.azure.com/subscriptions/yourSubscriptionId/resourceGroups/yourWebAppResourceGroup/providers/Microsoft.Web/sites/yourWebAppName/config/web
Find and Change the property: "http20Enabled": from true to false by clicking EDIT, Update value to “false” and then clicking in Save or PATCH.
I developing a simple android app, in which I am trying to get the incoming SMS.
I search alot tutorials and write all codes , no errors with code but not getting any required result also.
I start new project, add new class and extends it with BroadcastReceiver and write all mendatory method(like onReceive)in this class. I write Toast statment for testing. No errors or warning found during compiling. but unable to get responce of code written in BroadcastReceiver Class.(even toast is not displaying)
I didn't write any thing on Main activity.
I also write all permitions in mainifiset file like sms read write and receive and receiver code also.
Do I have to make any link between MainActivity and this new class.
Please help me...
public class IncomingSms extends BroadcastReceiver {
final SmsManager sms = SmsManager.getDefault();
String message ="";
public void onReceive(Context context, Intent intent) {
final Bundle bundle = intent.getExtras();
try {
if (bundle != null) {
final Object[] pdusObj = (Object[]) bundle.get("pdus");
for (int i = 0; i < pdusObj.length; i++) {
SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
String phoneNumber = currentMessage.getDisplayOriginatingAddress();
String senderNum = phoneNumber;
message = currentMessage.getDisplayMessageBody();
Log.i("SmsReceiver", "senderNum: "+ senderNum + "; message: " + message);
// Show Alert
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context,
"senderNum: "+ senderNum + ", message: " + message, duration);
toast.show();
} // end for loop
} // bundle is null
} catch (Exception e) {
Log.e("SmsReceiver", "Exception smsReceiver" +e);
}
}
}
and mainifest file have these entries
<receiver android:name=".IncomingSms">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
and
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>