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?
Related
I'm working on an basic reminder application which has a user interface capable to log user set dates to an sqlite database. To complete my application I'd like to have a service which starts and keep running in the background when the phone is restarted, so I can periodically check the database and display a notification message to the user if any of the dates are close.
I can start my service on startup (I can send LOG messages to Android Studio) but I can't display notifications. It seems the examples I have found always rely on an activity, but how would I have an activity without having the main app running? (and ofcourse thats the point of my background service, the user doesnt have to open the main app).
Q1: How can I display a Toast message from this service?
Q2: How can I display a notification from this service?
public class autostartservice extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
for (int i = 0; i < 40; i++) {
synchronized (this) {
try {
wait(1000);
} catch (Exception e) {}
Log.i("myDebug", "Just wait here couple second until the phone boots all the way");
}
}
Toast.makeText(context, "Look at this Toast! Cool uh?", Toast.LENGTH_SHORT).show();
}
}
}
All these kind of things uses a Context to show a Toast or a Notification. A Service "acts as" a Context, so you can do quite the same things as you do in an Activity. You only have to pay attention that a normal Service runs in the same Thread of the UserInterface, so if the Service is blocking (waiting some event in a Blocking way) even the UserInterface is blocked and Notifications or Toasts cannot be displayed while blocked/frozen.
I need to know if the user is using my application at the moment.
My idea is to make a method to make his status on in the first activity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin_page);
makemeonline();
}
But how can I know if the user didn't just close the application or move it to the background?
You can override the onPause function. In your onPause function, do something like this.
#Override
public void onPause() {
super.onPause();
makeUserIdle();
}
You can not really detect if the user is not connected to internet as I suppose makeMeOnline is calling an API to get the user status posted to some server. If you want the user to track user offline as well, then you might just consider saving the values in your sqlite database and then upload the behaviour data later to the server through another API call when the device is connected to internet.
If you integrate google analytics with your project, you can have an estimate of how many users are currently using your application in the play developer console as well.
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.
In my use case I try to send data (larger than 100K) from a wear companion app to the wear app. I'm leveraging WearCompanionLibrary (WCL, https://github.com/googlesamples/android-WearCompanionLibrary). I'm aiming for the low level Channel API, the sample app (https://github.com/googlesamples/android-WclDemoSample) is somewhat reverse: it sends an image from the wear to the companion.
But I don't even get to that point, because even though I execute WearManager.initialize(getApplicationContext()); in both the wear app's and the mobile app's onCreate(), when it comes to send the data the wearManager.getConnectedNodes(); returns empty node set.
Consequently if I try to set wearManager.removeCapabilities(CAPABILITY_FILE_PROCESSOR); in the main activity of the wear app (which will receive the data), I get an exception from https://github.com/googlesamples/android-WearCompanionLibrary/blob/master/WCL/src/main/java/com/google/devrel/wcl/WearManager.java#L594
I don't understand why. Debugging into WCL it properly calls
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addApi(Wearable.API)
.addConnectionCallbacks(new MyConnectionCallbacksListener())
.addOnConnectionFailedListener(new MyConnectionFailedListener())
.build();
mGoogleApiClient.connect();
under the hood: https://github.com/googlesamples/android-WearCompanionLibrary/blob/master/WCL/src/main/java/com/google/devrel/wcl/WearManager.java#L140
I use API 25 Wear emulator, I include 10.0.1 Play Services in the companion app part because I use GcmTaskService.
import com.google.devrel.wcl.WearManager;
public class MyWearApp extends Application {
private static MyWearApp application;
public MyWearApp getInstance() {
return application;
}
#Override
public void onCreate() {
super.onCreate();
WearManager.initialize(getApplicationContext());
application = this;
}
...
}
Alternatively, if you have any tips on how to achieve this absolutely simple task of sending <100K binary data from one node to another, please let me know. I tried DataLayer API in several different ways (DataMap, notification), with no satisfaction.
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.