I'm using Sinch SDK for video calls in my app. The app has a MainActivity.java which opens several fragments. The structure/flow of the app is like this:
MainActiivty is the launcher/starting activity
It opens LoginFragment. User inputs their credentials in the login fragment.
Loginfragment authenticates information with my own server and generates a unique userName for Sinch Video SDK login.
Login Fragment sends the unique userName to the MainActivity. The MainActivity executes the following code to login Sinch Video SDK
getSinchServiceInterface().setStartListener(this);
if (!getSinchServiceInterface().isStarted()) {
getSinchServiceInterface().startClient(userName);
}
MainActivity.java opens ProfileFragment.java. In this fragment the user enters the name of the callee device.
ProfileFragment.java sends callee userName to the MainActivity. The MainActivity executes the following code to call the callee device
getSinchServiceInterface().callUserVideo(calleeUserName);
After executing this, the caller device doesn't get any callback when the callee device picks up the call. So as a workaround, I'm monitoring the onLogMessage() in SinchService to look for onSessionEstablished tag.
When the mentioned tag is received in onLogMessage in SinchService.java, I execute the following code.
Call call = getSinchServiceInterface().getCall(mCalleeID);
if (call != null) {
if (!mAddedListener) {
call.addCallListener(new SinchCallListener());
mAddedListener = true;
}
if (call.getState() == CallState.ESTABLISHED) {
openVideoCallFragment(mCallId);
}
} else {
Log.e(TAG, "Started with invalid callId, aborting.");
}
However upon execution of this method, it just gives the following log message:
Started with invalid callId, aborting.
I'm not sure how can I fix it or how can I know when the callee device has pickedup the call.
My MainActivity.java extends BaseActivity.java provided in the sample app of the Sinch SDK.
Related
As soon as I receive a push notification from my app I want to trigger the KeyguardManager to launch the fingerprint/pass code screen to open the phone from lock screen so that person can enter the phone and unlock the device.
I want to trigger this programmatically similar to when we click on any notification from lock screen we get the fingerprint/pass-code screen.
I did a lot of RnD but didn't find any solution, this is one of the challenging use case task given to me in class, I have been exploring a lot from quite few weeks with no success at all.
Did tried Broadcast receiver with BiometricManager and many things with no success, any lead will be very helpful.
As soon as you receive push message, onNotificationReceived() (or some other method if you use some 3rd party libs) method gets called as below. from there, you can launch your Main screen where you have written biometric/unlocking code.
class MyReceiver : PushReceiver {
override fun onNotificationReceived(message: Message) : Boolean {
//Launch your MainActivity where you can show Unlock screen.
return super.onNotificationReceived(message);
}
}
I am creating a video calling app and have the following code which is called when the application receives a push notification - it unlocks the screen and presents an 'incoming call' user interface:
public class MainActivity extends ReactActivity {
#Override
protected String getMainComponentName() {
return "x";
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
}
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
}
This works fine when a call is incoming - the user can interact with the app using the UI presented. However, the problem is is that if the app is in the foreground and the phone is then locked, when the unlock button is pressed on the side of the phone, the app is displayed, instead of the keyguard / lock screen being displayed. It permanently allows access to the app if it is in the foreground and the phone is locked and the unlock button is pressed.
I want the app to appear when the it receives a push notification and the screen is locked, but I also want the user to be able to lock the device fully and not give the user access to the app after pressing the lock button.
How can I achieve this?
As far as I know the best solution to that problem is having multiple types of activities.
In the first activity (calling activity) you set setShowWhenLocked and setTurnScreenOn to true (like you did).
When a call comes in, you start the calling activity which handles the call, because you set the two attributes, the activitiy will be shown to the user even if the device is locked.
Furthermore, while the call activitiy is active, the user will be able to "lock" his device (i.e. press the power button), and when he unlocks he will be presented with the calling activity again (without entering the code).
This is the same behaviour as most default android calling/phone apps have.
The second activity is used for your other logic, that should only be accessible when the user really unlocks his phone. (i.e. enter the code)
So, when the phone call is ended, you start the second activity from the calling activity, e.g. like this:
Intent intent = new Intent(this, SecondActivity.class);
this.startActivity(intent);
where this is the instance of the calling activity
The just started SecondActivity will then automatically be locked behind the lockscreen (i.e. not accessible without unlock) if the phone was locked before.
I just tested this behaviour in a small test project, if you need further assistance, just ask.
In my VoIP app (baresip), I solved the problem by calling requestDismissKeyguard() function also when power button is pressed to unlock the device. That can be detected by registering a broadcast receiver with IntentFilter(Intent.ACTION_SCREEN_ON). Then if the device is locked with secured keyguard, requestDismissKeyguard() will ask for a PIN code or password before the user can access the app.
After user logged in successfully, there will be another api call to get the user information.
But before the response I will close the activity and start the home activity.
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
//save token
// call REST service to get user info and update the user records on DB.
// update the notification token info
//go to home page
Intent intent = new Intent(SigninActivity.this, HomeActivity.class);
startActivity(intent);
finish();
}
How can I make the call REST calls outside the activity. So App can handle the onReponse even after I close the Activity.
In General How can we call the API to do the background activity (eg: update database.) without any interaction . (response doesn't depend on activity)
The easiest solution would be to use static method. You can call those methods from anywhere.
If you want to update UI elements inside that method, pass the UI elements as parameters to the static method.
You could run a service(async) in the background minimize the first app and onResponse kill the first app and start the 2nd. And just access the data from the first.
There are two ways of doing this
Calling the user information API from the home activity (This is what I prefer).
While logging in, start a Service which makes the user information API call. Since Services are independent of UI and can run in the background starting the home activity and stopping the current one doesn't have any effect on the service. Once you get the response in the Service, create a broadcast(Or use EventBus) to send the response to home activity.
I have code like this for a watchface in Android Studio. I'm putting a random integer in the datamap so that the receiving side on the phone app can detect it as having been updated. I set this code in onConnected with the intent that every time the watchface is installed or 'chosen' by the user again, it will update data on the watchface - the main app receives this 'installed' status and then sends back updated information to the watch.
public class MyWatchFace extends CanvasWatchFaceService {
///
private class Engine extends CanvasWatchFaceService.Engine implements
DataApi.DataListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
#Override
public void onConnected(#Nullable Bundle bundle) {
Wearable.DataApi.addListener(mGoogleApiClient, this);
PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/installed");
putDataMapReq.getDataMap().putInt(INSTALLED, new Random().nextInt());
PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
putDataReq.setUrgent();
Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq)
.setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(DataApi.DataItemResult dataItemResult) {
Log.d(TAG, "Sending Install Status was successful: " + dataItemResult.getStatus()
.isSuccess());
}
});
}
The problem is that this section of code
Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq)
.setResultCallback
never seems to be called when I debug it, while installing or choosing the watchface again. I have to go to the phone app and update information on there for the information to be sent back to the watch.
I originally put the callback in the onCreate method of the Engine, but that was never called either. This is also where I create and connect the mGoogleApiClient, which IS successfully called.
Is there a more appropriate method to put this installed update code in? Why is it never being called in these 2 methods?
Everything else about the watch works fine - it successfully retrieves data from the phone app when the phone app data changes. PS, I use the same mGoogleApiClient to retrieve this phone data to also send the install status, in case you think that might be a problem. Do I have to create two separate clients?
I just recently added the capability of my app to check for updates on our local server (this app is not published in the Google Play store. It's going to be used internally and there is no internet connection where it will be used. Don't ask. That's how it is :) ). I keep track of updates by checking a certain table in SQL Server and if my app's version is lower than what is indicated in this table, I download the new APK from an internal website (LAN only) then install the APK. I also have another application in the device that listens for PACKAGE_ADDED broadcasts. I can capture the broadcast successfully.
The problem is, after installation, the broadcast receiver starts the app by calling the following.
public class PackageInstalledBroadcastReceiver extends BroadcastReceiver {
private final String MY_PACKAGE_NAME = "com.company.packagename";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) {
String packageName = intent.getData().getSchemeSpecificPart();
if (packageName.equalsIgnoreCase(MY_PACKAGE_NAME)) {
Intent i = new Intent();
i.setClassName(MY_PACKAGE_NAME, MY_PACKAGE_NAME + ".LoginActivity");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
}
But it takes a long time for the app to start. The user might think that nothing is happening, so he/she can start the app manually by clicking the app's icon. If the user clicks the app's icon, the app starts immediately. After a while, the activity that the broadcast receiver started is also opened. So now, I end up with two instances of my app in the same activity (LoginActivity). I can say that this is the case, because if I press the Back key on the device from the LoginActivity, I still end up in another LoginActivity and if I press the Back key again, I end up on the device's desktop.
You have two problem in your question:
The fist, why your BroadcastReceiver take a long time to start your activity.
It have not enough information for stoving this.
The second your want to make your activity have a single instance.
Android provide a way to do that:
Step one: Visit your application androidmanifest file
Step two: Find your activity declaration.
Step there: Add the following property android:launchMode = "singleInstance"
The reference here:
P/s: If you could provide my some more information of your fist problem. Please create a new question. Hope you resolve it.