How to use wireguard tunnel library? - java

I want to create a third-party VPN app by using the library com.wireguard.android:tunnel (1.0.20211029) Can anyone help me to provide me any good resources or guide me?
In my app I am importing .config file from file manager now how to connect that file to server using tunnel library . I am using java .
I did followed https://github.com/WireGuard/wireguard-android but The app wraps a lot of the tunnel library code. I am looking for a simple example of how to use the tunnel library directly without all the wrapping with TunnelManager and ObservableTunnel.
Please guide me

UPD: added request intent, because it is necessary on first connection
UPD 2: I have a made a step-by-step guide: https://github.com/Anton2319/Anton2319/blob/master/articles/wireguard-guide/article.md
I think this code will work for you:
In your main activity, use this (replace IP, pubkey and privatekey):
Tunnel tunnel = new WgTunnel();
Intent intentPrepare = GoBackend.VpnService.prepare(this);
if(intentPrepare != null) {
startActivityForResult(intentPrepare, 0);
}
Interface.Builder interfaceBuilder = new Interface.Builder();
Peer.Builder peerBuilder = new Peer.Builder();
Backend backend = new GoBackend(this);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
try {
backend.setState(tunnel, UP, new Config.Builder()
.setInterface(interfaceBuilder.addAddress(InetNetwork.parse("10.0.0.2/32")).parsePrivateKey("privatekeybase64").build())
.addPeer(peerBuilder.addAllowedIp(InetNetwork.parse("0.0.0.0/0")).setEndpoint(InetEndpoint.parse("yourhost:51820")).parsePublicKey("pubkeybase64").build())
.build());
} catch (Exception e) {
e.printStackTrace();
}
}
});
In the same package as your main activity, create this class:
package package.name.here;
import com.wireguard.android.backend.Tunnel;
public class WgTunnel implements Tunnel {
#Override
public String getName() {
return "wgpreconf";
}
#Override
public void onStateChange(State newState) {
}
}
In AndroidManifest.xml:
<application ...>
<service android:name="com.wireguard.android.backend.GoBackend$VpnService" android:permission="android.permission.BIND_VPN_SERVICE" android:exported="true">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
</application>
<uses-permission android:name="android.permission.INTERNET" />

in my case the dns address needed to be added and I added it to anton2319's code and the vpn worked. Like this. Thank you anton2319.
backend.setState(tunnel, UP, new Config.Builder()
.setInterface(interfaceBuilder.addDnsServer(InetAddress.getByName("your dns adress")).addAddress(InetNetwork.parse("10.0.0.2/32")).parsePrivateKey("privatekeybase64").build())

Related

How to solve- Onesignal push notification not coming to Android device if the app is not opened for a while?

In my Android application, I am using One Signal push notification service to send push notifications. I have done all the settings according to document as mentioned.
After setting up all these things, I have created one service class of one signal like below-
NotificationExtenderBareBonesExample.java
public class NotificationExtenderBareBonesExample extends NotificationExtenderService {
public static String first_screen;
#Override
protected boolean onNotificationProcessing(OSNotificationReceivedResult receivedResult) {
SharedPreferences.Editor editor = getApplicationContext().getSharedPreferences("NOTIFY_PREF", MODE_PRIVATE).edit();
editor.putString("notify_msg", receivedResult.payload.groupMessage);
editor.putString("notify_key", receivedResult.payload.groupKey);
editor.apply();
first_screen = receivedResult.payload.groupMessage;
return false;
}
}
I have also created another class to handle the received push notification like below-
ExampleNotificationReceivedHandler.java
public class ExampleNotificationReceivedHandler implements OneSignal.NotificationReceivedHandler {
#Override
public void notificationReceived(OSNotification notification) {
JSONObject data = notification.payload.additionalData;
String customKey;
if (data != null) {
customKey = data.optString("customkey", null);
if (customKey != null)
Log.i("OneSignalExample", "customkey set with value: " + customKey);
}
}
}
Then, in my Activity class, I have initialized One Signal like below-
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.unsubscribeWhenNotificationsAreDisabled(true)
.setNotificationReceivedHandler(new ExampleNotificationReceivedHandler())
.setNotificationOpenedHandler(new MyNotificationOpenedHandler(this))
.init();
At last in my AndroidManifest file, I have declared the service like below-
<service
android:name="com.rokomari.new_package.notification_check.NotificationExtenderBareBonesExample"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE">
<intent-filter>
<action android:name="com.onesignal.NotificationExtender" />
</intent-filter>
</service>
The push notification was coming, if the app is being used recently, but the problem was still there as it is mentioned in my question. So, I have checked few more solutions and applied in my project like below-
I made my application a system app and added one authentication service with that.
I also added one Broadcast-Receiver class like below-
BootReceiver.java
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
Intent startServiceIntent = new Intent(context, NotificationExtenderBareBonesExample.class);
context.startService(startServiceIntent);
Intent notificationServiceIntent = new Intent(context, NotificationExtenderBareBonesExample.class);
context.startService(notificationServiceIntent);
}
}
}
And declared this in my AndroidManifest file-
<receiver
android:name="com.rokomari.new_package.notification_check.BootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
After doing all these I am still having the same problem.
---- The Problem is -----
When I am using app(opening the app) regaularly the push notification from one signal is coming whether the app is in background or not. But when I am not using the app for a while it's not coming. In addition, for some devices mainly Xiomi the push notification is not coming at all.
After making some changes in Xiomi device like below-
*** Xiaomi - Make sure "Auto-start" property enabled for your app in the settings.**
After changing settings, the push notification came once. But I need a solution programmatically to send push notification to cover all the devices. If it is not possible yet with One Signal, then I like to know how apps like facebook, whatsapp send push notification?

How to detect outgoing call number in Android Q

I'm unable to get outgoing call number in Android Q.
I've registered receiver in the manifest with this intent filter android.intent.action.NEW_OUTGOING_CALL and in code i'm detecting outgoing phone number like this
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
String nr = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
But i can never get the outgoing call number in Android Q, is there a workaround to get this number differently or since Android Q it is completely impossible to detect outgoing call number?
Edit: It works with previous android versions
You need to add PROCESS_OUTGOING_CALLS permission
Create OutgoingCallReceiver
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
public class OutgoingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
TelephonyManager tm = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
if (tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) {
String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
}
}
}
Add required permissions to read outcomming call in AndroidManifest file
<uses-permission android:name="android.permission.NEW_OUTGOING_CALL" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Request permissions at runtime
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS, Manifest.permission.READ_PHONE_STATE},
1);
}
Add OutgoingCallReceiver in AndroidManifest file
<receiver
android:name=".application.services.OutgoingCallReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
This code will work fine with you, but when you need to upload your application on Google play, It is ok with NEW_OUTGOING_CALL and READ_PHONE_STATE permission but,
you will receive a policy notice from playStore as:
Your app manifest requests the Call Log permission group (e.g. PROCESS_OUTGOING_CALLS)
It must be actively registered as the default Phone or Assistant handler on the device.
in this case you have 2 solution only if you want to read OutCommingCall Number:
Send declaration form to google declaration form
Or Make your application dialer app
Check Developer Policy Center
From the documentation for android.intent.action.NEW_OUTGOING_CALL:
This constant was deprecated in API level 29. Apps that redirect
outgoing calls should use the CallRedirectionService API. Apps that
perform call screening should use the CallScreeningService API.
https://developer.android.com/reference/android/content/Intent
So I would implement this API first and check if it works as expected.
Answered in Kotlin, not Java:
From sdk >=29 (Android 10 and up) you can register your app as a CallRedirectionService, "to interact between Telecom and its implementor for making outgoing call with optional redirection/cancellation purposes."
This removes the need to create a custom BroadcastReceiver.
1. On your AndroidManifest.xml file:
<service
android:name=".MyCallRedirectionService"
android:exported="true"
android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallRedirectionService" />
</intent-filter>
</service>
2. Create MyCallRedirectionService:
class MyCallRedirectionService : CallRedirectionService() {
override fun onPlaceCall(
handle: Uri,
initialPhoneAccount: PhoneAccountHandle,
allowInteractiveResponse: Boolean
) {
// We can get the outgoing number from the handle parameter:
Log.i("Phone Number:", handle.toString())
}
}
3. Use the RoleManager class to prompt the user to select your app as their CallRedirectionService:
In this case, I'm requesting as soon as the app is created, over on the MainActivity onCreate() method:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (!isRedirection())
roleAcquire(RoleManager.ROLE_CALL_REDIRECTION)
}
Here are the used functions:
private fun isRedirection(): Boolean {
return isRoleHeldByApp(RoleManager.ROLE_CALL_REDIRECTION)
}
private fun isRoleHeldByApp(roleName: String): Boolean {
val roleManager: RoleManager? = getSystemService(RoleManager::class.java)
return roleManager!!.isRoleHeld(roleName)
}
private fun roleAcquire(roleName: String) {
val roleManager: RoleManager?
if (roleAvailable(roleName)) {
roleManager = getSystemService(RoleManager::class.java)
val intent = roleManager.createRequestRoleIntent(roleName)
startActivityForResult(intent, 1)
} else {
Toast.makeText(
this,
"Redirection call with role in not available",
Toast.LENGTH_SHORT
).show()
}
}
private fun roleAvailable(roleName: String): Boolean {
val roleManager: RoleManager? = getSystemService(RoleManager::class.java)
return roleManager!!.isRoleAvailable(roleName)
}

Load data if connected to the Internet

Helle Stack community,
I created a simple app that loads a json and loads the data in a recyclerview.
The recyclerview includes cardviews.
The activity shows me a blank page if I haven't any internet connection,
but normally I want to see some blank cardviews like in the 9GAG app.
In the 9GAG app you get all data on swipe the display.
My app should load all data on internet connection is available. I googled something about broadcast receiver, but can't find a simple example for my need.
Maybe someone can show me a simple example or the way to do some action like in the 9GAG app. Info: The app is for api 21 User.
I would appreciate it.
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (Network.isNetworkAvailable(Constants.ApplicationContext)) {
} else {
}
}
}
public class Network {
public static boolean isNetworkAvailable(Context context) {
int retriesNum = Constants.checkConnectionRetriesNum;// a number that I put as 5 for retries to make consideration for bad connections
if(context!=null)
while (retriesNum > 0) {
try {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo network = connectivityManager.getActiveNetworkInfo();
boolean isConnected = network != null &&
network.isConnectedOrConnecting();
if (isConnected) {
return true;
} else {
network = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
isConnected = network != null && network.isConnectedOrConnecting();
if (isConnected) {
return true;
} else {
network = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
isConnected = network != null && network.isConnectedOrConnecting();
if (isConnected) {
return true;
} else {
retriesNum--;
}
}
}
}catch (Exception ex){
return true;
}
}
return false;
}
Use a BroadcastReceiver that gets notified, when the connection state changes. It is very important that you register it in your manifeset!
Add a class, similar to this to your project:
public class NetworkChangedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Network state changed!
// Check if the user connected using ConnectivityManager.getActiveNetworkInfo()
}
}
Add it to your manifest file, so the systems knows it should notify you:
<manifest>
...
<application>
...
<receiver
android:name=".NetworkChangedReceiver"
android:process=":remote">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
...
</application>
</manifest>
Edit:
From the docs:
Apps targeting Android 7.0 (API level 24) do not receive CONNECTIVITY_ACTION broadcasts if they register to receive them in their manifest, and processes that depend on this broadcast will not start. This could pose a problem for apps that want to listen for network changes or perform bulk network activities when the device connects to an unmetered network. Several solutions to get around this restriction already exist in the Android framework, but choosing the right one depends on what you want your app to accomplish.
Note: A BroadcastReceiver registered with Context.registerReceiver()
continues to receive these broadcasts while the app is running.
I didn't knew about this, so thanks to #Paul Nie for letting me know :D
I can't really help further at this point. But this seems like a good point to start some research about this topic: https://developer.android.com/topic/performance/background-optimization.html#connectivity-action

Check if Download Manager downloaded the file

How can I check if file has been downloaded and run its installation? I have a code:
public void downloadUpdate(String url){
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Downloading...");
request.setTitle("App Update");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
String name = URLUtil.guessFileName(url, null, MimeTypeMap.getFileExtensionFromUrl(url));
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, name);
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
}
To check whether the download manager downloaded the file, you must implements your BroatcastReceiver.
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0));
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Cursor cursor = manager.query(query);
if (cursor.moveToFirst()) {
if (cursor.getCount() > 0) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status == DownloadManager.STATUS_SUCCESSFUL) {
String file = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
// So something here on success
} else {
int message = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_REASON));
// So something here on failed.
}
}
}
}
}
However, I am not sure whether you can install the APK programmatically. For security reason, I don't think you can. For application update, I think you should use google versioning control. When you re-deploy your app using different version number, the users should able to update automatically (unless user turn off at google play). Hope that this will help.
Update
You do not need to call the method that I mention. You just need to declare your broadcast receiver at your manifest xml file and DownloadManager will call at when download complete. The xml look something like below:
<receiver
android:name=".BroadcastReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
<action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED" />
</intent-filter>
</receiver>
This is relatively an easy method. It worked for me:
You need to add the <receiver> tag in the manifest file as follows:
<application>
<receiver
android:name= "com.example.checkDownloadComplete" <!-- add desired full name here -->
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>
</application>
This will register a Broadcast Receiver for an event where your download is completed. This will call the onReceive() method in your class as soon as download completes. Remember that you need to extend the BroadcastReceiver class, but not implement it. I declared a boolean variable as a toggle to check completion of download.
Hence, your Java class will be something like:
public static class checkDownloadComplete extends BroadcastReceiver{
public static boolean isDownloadComplete= false;
#Override
public void onReceive(Context context, Intent intent) {
isDownloadComplete = true;
Log.i("Download completed?", String.valueOf(isDownloadComplete));
}
}
To wait until or check whether your download has completed from any other class, use the following simple code in the desired appropriate place:
while(!checkDownloadComplete.isDownloadComplete){
// add necessary code to be executed before completion of download
}
//code after completion of download
But remember that if you need to check it multiple times in your project, then you'll need to reset the value of isDownloadComplete beforehand.

Check if IntentService started on boot is still running

Into manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Into application:
<service android:name="Myservice"/>
<receiver android:name="com.myapp.Onstart"> <!-- Tested also only .Onstart -->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Onstart.java:
package com.myapp;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class Onstart extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")){
context.startService(new Intent(context, Myservice.class));
}
}
}
Myservice.java:
package com.myapp;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
public class Myservice extends IntentService
{
public Myservice() {
super("Myservice");
}
#Override
protected void onHandleIntent(Intent intent) {
int n=0;
while(true)
{
if (i==20) {
stopSelf();
}
i = i++;
Log.i("Test", "n."+n++);
try {
Thread.sleep(10000);
}
catch (InterruptedException e)
{ }
}
}
}
Launching the application manually is shown the Main.java, and I want to know there (in Main.java) if my IntentService Myservice is still running. How to do it?
While I know that your question is to whether it's running or not, I do not see why would you need to know. Since IntentService works on demand.
IntentService is a base class for Services that handle asynchronous
requests (expressed as Intents) on demand. Clients send requests
through startService(Intent) calls; the service is started as needed,
handles each Intent in turn using a worker thread, and stops itself
when it runs out of work.
Also, from Context.startService(Intent) call doc:
If the service is being started or is already running, the
ComponentName of the actual service that was started is returned; else
if the service does not exist null is returned.
If you must, you can check the startService(Intent) return parameter.
Edit: It seems that you need an started service handled solely by you, not the system. This will allow you to have your own stop condition. Please refer to Services and Services Guide on how to use them.
References:
IntentService
startService(Intent service)
Services
Services Guide

Categories

Resources