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.
Related
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())
I'm new to Android coding but I already had played with java.
I want to open or bring my app back once it is in background.
I've been searching around but nothing seems to work.
I have a function of a class that is called every time a notification is received which is CordovaNotificationReceivedHandler and it is instantiated by the OneSignal init as per the code below.
OneSignal.init(this.cordova.getActivity(),
googleProjectNumber,
appId,
new CordovaNotificationOpenedHandler(notifOpenedCallbackContext),
new CordovaNotificationReceivedHandler(notifReceivedCallbackContext)
);
Trying to get my application to be reordered and displayed, even if the user is in another application, I made the following changes:
OneSignal.init(this.cordova.getActivity(),
googleProjectNumber,
appId,
new CordovaNotificationOpenedHandler(notifOpenedCallbackContext),
new CordovaNotificationReceivedHandler(this.cordova.getActivity(), notifReceivedCallbackContext));
In the body of the function that is called when receiving a push notification I added the following code:
Intent it = new Intent("intent.my.action");
it.setComponent(new ComponentName(contextActivy.getPackageName(), MainActivity.class.getName()));
it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
contextActivy.getApplicationContext().startActivity(it);
this.handleActivityLifecycleHandler();
Como a classe ficou após a modificação:
private class CordovaNotificationReceivedHandler implements NotificationReceivedHandler {
private CallbackContext jsNotificationReceivedCallBack;
private Context contextActivy;
public CordovaNotificationReceivedHandler(Context contextActivy, CallbackContext inCallbackContext) {
jsNotificationReceivedCallBack = inCallbackContext;
this.contextActivy = contextActivy;
}
#Override
public void notificationReceived(OSNotification notification) {
Log.w("Got here","Aqui");
Intent it = new Intent("intent.my.action");
it.setComponent(new ComponentName(contextActivy.getPackageName(), MainActivity.class.getName()));
it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
contextActivy.getApplicationContext().startActivity(it);
this.handleActivityLifecycleHandler();
try {
CallbackHelper.callbackSuccess(jsNotificationReceivedCallBack, new JSONObject(notification.stringify()));
}
catch (Throwable t) {
t.printStackTrace();
}
}
}
The problem is that the application is not reordered to be applied or opened.
It is important to remember that I am assuming that the application should be open.
You can use this, It work fine.
Intent intent = new Intent("intent.my.action");
intent.setComponent(new ComponentName(this, yourActivity.class));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
startActivity(intent);
Don't Forget Add this in your activity in manifest
<intent-filter>
<action android:name="intent.my.action" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
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?
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)
}
I am trying to write an app that checks in with a server every X seconds.
I was able to make it work, but only when the application is running and active (not sure if it can be minimized, was not able to test it clearly) and the device is not locked. I would like for the checking to continue even if I lock the device or do other things on it.
From my searches, it seems like I should use service, but I was not able to figure out how to implement it with what I am trying to do. Or is there something else that could do this?
What I need to and failed to do is this:
User checks a CheckBox - start the service
Create the service and pass some information to it
Create an instance of my class in the service using the passed information
Call this instance's method every X seconds in a new thread (the method returns true/false)
Listen to ?something and if the method returns true then stop the service and notify user
If the user unchecks the CheckBox, stop the service.
I tried doing this, but I was unable to get any information out of the thread and out of the service. Is there a way to do so?
Starting the service from activity for example and binding it with your app
//make these 2 variables as fields in Activity for example
YourService yourService = null;
//this variable can be used for checking if your activity are binded already or not
boolean mBounded = false;
Intent mIntent = new Intent(this, YourService.class);
startService(mIntent);
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
mBounded = false;
yourService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
mBounded = true;
YourService.LocalBinder mLocalBinder = (YourService.LocalBinder) service;
yourService= mLocalBinder.getServerInstance();
}
};
Do not forget that you can use methods from Service in Activity only after it is bound to your Activity. In other words it is available only after onServiceConnected is executed.
So you have now service and activity who can communicate with each other.
For example you can call in Activity some public method of your Service, like
if (yourService != null)
yourService.test();
If you want to call your Activity methods in Service you should pass it to Service with simple setter.
If you want to stop Service its kinda easy too:
Intent mIntent = new Intent(this, YourService.class);
stopService(mIntent);
For doing request every X service:
1) You can do infinity separate thread inside Service and do request after delay for X seconds.
2) For checking every X seconds you can use something like AlarmManager.
3) Also its possible to use CountDownTimer inside your Service to do some requests to server.
If you want to create your Service after reboot if CheckBox was set, its easy too. So you should use simple BroadcastReceiver.
First of all you should save your CheckBox setting in SharedPreferences, then run your Service if you need.
public class SimpleReceiver extends WakefulBroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//run below code if you need, depends on your saved value of Checkbox in SharedPreferences
Intent serviceIntent = new Intent(context, YourService.class);
context.startService(serviceIntent);
}
}
And for sure dont forget to add in AndroidManifest information about your Service and Receiver to be sure it will run automatically after reboot.
<service
android:name=".package.YourService"
android:enabled="true"
android:exported="false"> </service>
<receiver
android:name=".package.SimpleReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action adroid:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>