I'm try to build a wear-app for my existing app.
I already have an SQLite Database in my Handheld-App, now i want to try to use them in my wear app.
Is their any possibility to send the database to the Wear or can i access the database on my handheld from the wear app?
My current idea is to transfer all items via Wearable.DataApi, but that's sounds not like the best solution.
For example, i don't believe that Google Keep transfer all the notes separately.
Anyone another idea?
I've found a quick Solution for transfering the whole database from phone to Smartwatch.
First i create a helper class which converts my database content into a json-string, that can be send to smartwatch by using the Wearable.DataApi:
DatabaseToJSON.java:
public class DatabaseToJSON {
DatabaseHandler dbhandler;
public DatabaseToJSON(Context context) {
dbhandler = new DatabaseHandler(context);
}
public JSONObject getJSON() throws JSONException{
Item[] item = null;
JSONObject pl = new JSONObject();
item = dbhandler.getItems();
dbhandler.close();
JSONArray jsonArray = new JSONArray();
for(int i=0;i<item.length;i++){
JSONObject val = new JSONObject();
try {
val.put("id", item[i].getID());
val.put("name", item[i].getName());
...
jsonArray.put(val);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pl.put(String.valueOf(j), jsonArray);
}
if(jsonArray.length()<1){
pl.put(String.valueOf(j),new JSONArray());
}
}
JSONObject result = new JSONObject();
result.put("data",pl);
return result;
} }
DemoActivity.java (Phone):
public class DemoActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
/** Android Wear **/
GoogleApiClient googleClient;
#Override
public void onStart(){
super.onStart();
googleClient.connect();
}
#Override
public void onStop(){
if (null != googleClient && googleClient.isConnected()) {
googleClient.disconnect();
}
super.onStop();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
googleClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
...
}
#Override
public void onConnected(Bundle bundle) {
DatabaseToJSON dbJson = new DatabaseToJSON(DemoActivity.this);
try {
JSONObject json = dbJson.getJSON();
new SendToDataLayerThread("/path", json.toString()).start();
} catch (JSONException e) {
e.printStackTrace();
}
}
class SendToDataLayerThread extends Thread {
String path;
String message;
SendToDataLayerThread(String p, String msg) {
path = p;
message = msg;
}
public void run() {
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleClient).await();
for (Node node : nodes.getNodes()) {
MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(googleClient, node.getId(), path, message.getBytes()).await();
if (result.getStatus().isSuccess()) {
Log.v("myTag", "Message: {" + message + "} sent to: " + node.getDisplayName());
}
else {
Log.v("myTag", "ERROR: failed to send Message");
}
}
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
DataLayerListenerService.java (wear)
public class DataLayerListenerService extends WearableListenerService {
#Override
public void onMessageReceived(MessageEvent messageEvent) {
if (messageEvent.getPath().equals("/path")) {
final String message = new String(messageEvent.getData());
// do what you want with the json-string
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor edit = pref.edit();
edit.putString("demo_json",message).apply();
}
else {
super.onMessageReceived(messageEvent);
}
}
Add to AndroidManifest.xml (wear)
<service android:name=".DataLayerListenerService" >
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
After receiving the json-string on your wear you can save them within a database on your wear or do something else with it...
I think thats the simplest way to transfer such data between handheld and wear device.
You probably wouldn't want to send an entire database to the wearable. Rather you should use the messaging protocols available (WearableListenerService) to you in order to communicate with the database that is already on the handheld.
Here are the docs on that: http://developer.android.com/training/wearables/data-layer/events.html.
Related
I want to WorkManager startWork() to be called every time the user connects to the internet through wifi or 3g/4g/5g.
It calls only one time at the start where I register it.
enqueuing work when a user signs in.
Worker.startWorkManager(SignInActivity.this);
startActivity(new Intent(SignInActivity.this,UsersActivity.class);
it never calls again whenever the user turns Wifi OFF and ON again regardless app is in foreground or background or app is killed through swiped from recent apps.
I want it to be called every time user turned Wifi OFF and ON in every scenario i.e foreground, background, or app is killed.
Worker.class
public class Worker {
public Worker(Context context, WorkerParameters workerParams) {
}
public static void startWorkManager(Context context) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
WorkManager.getInstance(context).enqueueUniqueWork(Constants.TAG_SYNC_DATA, ExistingWorkPolicy.KEEP, new OneTimeWorkRequest.Builder(SyncDataWorker.class)
.addTag(Constants.TAG_SYNC_DATA)
.setConstraints(constraints)
.build());
}
}
SyncDataWorker.class
public class SyncDataWorker extends ListenableWorker {
public SyncDataWorker(
#NonNull Context context,
#NonNull WorkerParameters params) {
super(context, params);
}
#NonNull
#Override
public ListenableFuture<Result> startWork() {
return CallbackToFutureAdapter.getFuture(completer -> {
AsyncCallback callback = new AsyncCallback() {
#Override
public void onFailure(Exception e) {
completer.setException(e);
}
#Override
public void onSuccess() {
completer.set(Result.success());
}
#Override
public void onRetry() {
completer.set(Result.retry());
}
};
new AsyncSyncData(getApplicationContext(), callback).execute();
return callback;
});
}
}
AsyncSynData.class
public class AsyncSyncData extends AsyncTask<Void, Void, Void> {
private final Context context;
ArrayList<message> messageArrayListNotSync;
ArrayList<unread_messages> unreadMessagesArrayList;
String user_id = "";
private AsyncCallback callback = null;
public AsyncSyncData(Context context, AsyncCallback callback) {
this.context = context;
messageArrayListNotSync = new ArrayList<>();
unreadMessagesArrayList = new ArrayList<>();
this.callback = callback;
}
#Override
protected Void doInBackground(Void... voids) {
AppDatabase db = AppDatabase.getAppDatabase(context);
user user = null;
ArrayList<user> userArrayList = new ArrayList<>(db.applicationDao().getAllUsers());
if (userArrayList.size() > 0) {
user = userArrayList.get(0);
}
messageArrayListNotSync = new ArrayList<>(db.applicationDao().getAllMessagesNotSync(!user_id.isEmpty() ? user_id : user.threadId));
unreadMessagesArrayList = new ArrayList<>(db.applicationDao().getUnreadMessageStatus());
System.out.println("messageArrayListNotSync: " + messageArrayListNotSync);
System.out.println("unreadMessagesArrayList: " + unreadMessagesArrayList);
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("user_id", !user_id.isEmpty() ? user_id : user.threadId);
Gson gson = new GsonBuilder().create();
JsonArray json_messages = gson.toJsonTree(messageArrayListNotSync).getAsJsonArray();
JsonArray json_unread_messages = gson.toJsonTree(unreadMessagesArrayList).getAsJsonArray();
jsonObject.put("messages", json_messages);
jsonObject.put("unread_messages", json_unread_messages);
RequestHandler.postRequest("/messages", jsonObject, context, new VolleyCallback() {
#Override
public void onSuccess(JSONObject result) {
final JSONObject finalResult = result;
try {
if (result != null && result.has("success") && result.getBoolean("success")) {
new AsyncDeleteUnreadMessagesList(context, unreadMessagesArrayList, new Callback() {
#Override
public void onCallbackCompleted() {
try {
ArrayList<com.app.amber.internet.DATABASE_OPERATIONS.schema.message> messagesToStore = new ArrayList<>();
JSONObject result = finalResult.getJSONObject("data");
JSONObject last_messages = result.getJSONObject("last_messages");
new AsyncUpdateLastMessage(context, last_messages, true, new Callback() {
#Override
public void onCallbackCompleted() {
try {
JSONArray json_messages_to_store = result.getJSONArray("messages");
JSONArray json_evetns_type_1 = result.getJSONArray("eventsType1");
JSONArray json_evetns_type_2 = result.getJSONArray("eventsType2");
for (int i = 0; i < json_messages_to_store.length(); i++) {
JSONObject data = json_messages_to_store.getJSONObject(i);
String id = data.getString("id"),
sender_id = data.getString("sender_id"),
receiver_id = data.getString("receiver_id"),
msg = data.getString("msg"),
type = data.getString("type"),
path = data.getString("path"),
download_status = data.getString("download"),
group_users = data.getString("group_users"),
group_message_status = data.getString("group_message_status");
boolean is_sender = false;
long data_created = data.getLong("date_created");
int is_read = 0;
com.app.amber.internet.DATABASE_OPERATIONS.schema.message message =
new com.app.amber.internet.DATABASE_OPERATIONS.schema.message(id, sender_id, receiver_id, msg, type, path, is_sender, data_created,
is_read, download_status, sender_id, group_users, group_message_status);
messagesToStore.add(message);
}
ArrayList<String> messageIdsType1 = new ArrayList<>();
ArrayList<String> messageIdsType2 = new ArrayList<>();
for (int i = 0; i < json_evetns_type_1.length(); i++) {
messageIdsType1.add(json_evetns_type_1.getJSONObject(i).getString("id"));
}
for (int i = 0; i < json_evetns_type_2.length(); i++) {
messageIdsType2.add(json_evetns_type_2.getJSONObject(i).getString("id"));
}
new AsyncStoreOldMessagesLocally(context, messagesToStore, new Callback() {
#Override
public void onCallbackCompleted() {
new AsyncUpdateMessageStatus(context, messageIdsType1, 1, new Callback() {
#Override
public void onCallbackCompleted() {
new AsyncUpdateMessageStatus(context, messageIdsType2, 2, new Callback() {
#Override
public void onCallbackCompleted() {
new AsyncUpdateMessageStatusList(context, messageArrayListNotSync, new Callback() {
#Override
public void onCallbackCompleted() {
sendCallBack();
}
}).execute();
}
}).execute();
}
}).execute();
}
}).execute();
} catch (Exception e) {
System.out.println("Exception occurred while getting data from data JSONObject received from service: " + e.toString());
e.printStackTrace();
sendCallBack();
}
}
}).execute();
} catch (Exception e) {
System.out.println("Exception occurred while parsing data JSONObject received from service: " + e.toString());
e.printStackTrace();
sendCallBack();
}
}
}).execute();
} else {
sendCallBack();
}
} catch (Exception e) {
System.out.println("Exception occurred while parsing webservice result: " + e.toString());
sendCallBack();
}
}
});
} catch (Exception e) {
System.out.println("exception occurred while parsing messaging lists: " + e.toString());
sendCallBack();
}
return null;
}
private void sendCallBack() {
if (callback != null) {
callback.onSuccess();
}
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
"WorkManager startWork() never calls when constraints are met"
"It calls only one time at the start where I register it."
The ListenableWorker can be recreated in some situations, a new instance of ListenableWorker with the same first ListenableWorker.id. But for it be recreated, it can't be finished. Here are some situations:
Some of the constraints do not matches anymore and it matches again
System was rebooted
Now here are some situations where it will be finished:
Some Exception was raised without treatment
completer.set(Result.success()) was called
completer.set(Result.failure()) was called
There are some situations in your code that the worker can be finished.
There are lots of calls to AsyncSyncData.sendCallBack, which can causes the call of completer.set(Result.success()) on the ListenableWorker instance. If it happens the ListenableWorker completes the job, so it will not be recreated anymore.
"I want to WorkManager startWork() to be called every time the user connects to the internet through wifi or 3g/4g/5g."
The WorkManager alone won't create a new instance of the ListenableWork every time the user connects to Internet. The WorkManager is a API to schedule tasks, and the constraints defined in the ListenableWork are used to not start it while them are not matched, after the ListenableWork finishes, how was discussed above, this task is finished, so no more to do.
If you want to listen to some connectivity changes, you should use ConnectivityManager.registerNetworkCallback and then when the user connects to, you do what you want. Here are some examples that could help you
to do it.
I am using Tone Analyzer of IBM Watson in my Android Code,but i keep getting java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
Following is my code
public class MainActivity extends AppCompatActivity {
final ToneAnalyzer toneAnalyzer =
new ToneAnalyzer("2018-01-19");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JSONObject credentials = null; // Convert the file into a JSON object
try {
credentials = new JSONObject(IOUtils.toString(
getResources().openRawResource(R.raw.credentials), "UTF-8"
));
String username = credentials.getString("username");
String password = credentials.getString("password");
toneAnalyzer.setUsernameAndPassword(username, password);
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Button analyzeButton = (Button)findViewById(R.id.analyze_button);
analyzeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
EditText userInput = (EditText)findViewById(R.id.user_input);
final String textToAnalyze = userInput.getText().toString();
ToneOptions options = new ToneOptions.Builder()
.addTone(Tone.EMOTION)
.html(false).build();
toneAnalyzer.getTone(textToAnalyze, options).enqueue(
new ServiceCallback<ToneAnalysis>() {
#Override
public void onResponse(ToneAnalysis response) {
Log.i("Hii", "onResponse: "+response.getDocumentTone());
List<ToneScore> scores = response.getDocumentTone()
.getTones()
.get(0)
.getTones();
String detectedTones = "";
for(ToneScore score:scores) {
if(score.getScore() > 0.5f) {
detectedTones += score.getName() + " ";
}
}
final String toastMessage =
"The following emotions were detected:\n\n"
+ detectedTones.toUpperCase();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(),
toastMessage, Toast.LENGTH_LONG).show();
}
});
}
#Override
public void onFailure(Exception e) {
e.printStackTrace();
}
});
}
});
}
}
Can somebody point out what am i doing wrong. I have kept my credentials.json file in raw folder.
I tried writing every emotion in my Android App but i keep getting no response. Any help would be greatly appreciated.
Hello I have implemented pusher for realtime chat and subscribing to pusher channel , but I have many activities and fragments where i want to listen to pushr events . I have added this code in every activity/fragment but the problem is that it creates multiple subscriptions for every id . I know that i have to use Singleton for this can anyone point me in the right direction to achieve this ?
Here is the code i am writing in every activity/fragment
private PusherOptions options;
private Channel channel;
private Pusher pusher;
options = new PusherOptions();
options.setCluster("ap2");
pusher = new Pusher("afbfc1f591fd7b70190f", options);
pusher.connect();
profile_id = Global.shared().preferences.getString("PROFILE_ID", " ");
channel = pusher.subscribe(profile_id);
channel.bind("message",
new SubscriptionEventListener() {
#Override
public void onEvent(String s, String s1, final String data) {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
JSONObject result = new JSONObject(data);
String message = result.getString("message");
String time = result.getString("time");
String reId = result.getString("recieverId");
new_message = message;
getConvoData(k, message);
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println("DATA ====>>" + data);
}
});
}
});
okay so after trying for a while i figured it out my self i created a global class and just added pusher code to it so that it maintains just one connection for the entire lifecycle of the app
public class Global extends MultiDexApplication {
#Override
public void onCreate() {
super.onCreate();
SharedPreferences preferences = sharedInstance.getSharedPreferences(sharedInstance.getString(R.string.shared_preferences), Context.MODE_PRIVATE);
sharedInstance.preferences = preferences;
connectTopusher();
}
public void connectTopusher() {
PusherOptions options;
Channel channel;
Pusher pusher;
options = new PusherOptions();
options.setCluster("ap2");
pusher = new Pusher("afbfc1f591fd7b70190f", options);
pusher.connect();
String profile = Global.shared().preferences.getString("PROFILE_ID", "");
channel = pusher.subscribe(profile);
channel.bind("message",
new SubscriptionEventListener() {
#Override
public void onEvent(String s, String s1, final String data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
try {
JSONObject result = new JSONObject(data);
String message = result.getString("message");
String time = result.getString("time");
String reId = result.getString("recieverId");
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println("DATA ====>>" + data);
}
});
}
});
channel.bind("status_change", new SubscriptionEventListener() {
#Override
public void onEvent(String s, String s1, final String data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
try {
JSONObject result = new JSONObject(data);
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println("DATA ====>>" + data);
}
});
}
});
}
You can expose channel in your Global class. That will allow you to call bind and unbind in your fragments, when they are in the foreground.
connectToPusher should just create a channel and subscribe to it.
In Global.java:
private Channel channel;
public void connectTopusher() {
PusherOptions options;
Pusher pusher;
options = new PusherOptions();
options.setCluster("ap2");
pusher = new Pusher("afbfc1f591fd7b70190f", options);
pusher.connect();
String profile = Global.shared().preferences.getString("PROFILE_ID", "");
this.channel = pusher.subscribe(profile);
}
public Channel getChannel(){
return this.channel;
}
And then in your activity/fragment you can bind/unbind your listeners to when they are resumed/paused - just keep a reference to it like this:
YourActivity.java (could also be your Fragment)
private SubscriptionEventListener messageListener = new SubscriptionEventListener(){
#Override
public void onEvent(String channel, String event, String data) {
//TODO: do something with events
}
}
//Bind when the listener comes into the foreground:
#Override
protected void onResume() {
super.onResume();
((Global) getActivity().getApplication()).getChannel().bind("message", messageListener);
}
//Make sure to unbind the event listener!
#Override
protected void onPause() {
super.onPause();
((Global) getActivity().getApplication()).getChannel().unbind("message", messageListener);
}
I hope this helps :)
Currently, I have a Service that is supposed to keep a socket.io connection open for multiple different Activitys to use. One of the biggest functions of the application is to update an album-art gallery whenever a song is added to a playlist. The Node.js server broadcasts if a song is added, and my goal is for the SocketService to update the UI when .on("song added"... is triggered. However, currently, I cannot figure out how to transfer the incoming data to the UI from the SocketService. How would I go about doing this?
For reference:
The "song add" command from the server emits a JSONObject.
public class SocketService extends IntentService {
Socket socket;
String roomID;
String userID;
ArrayList<JSONObject> queuedSongs;
ArrayList<JSONObject> suggestionSongs;
int users;
public SocketService() {
super("SocketService");
}
#Override
protected void onHandleIntent(Intent intent) {
userID = intent.getExtras().getString("userid", "0");
Log.i("SocketService", "userID=" + userID);
roomID = intent.getExtras().getString("code");
Log.i("SocketService", "roomID=" + roomID);
super.onCreate();
try {
socket = IO.socket("server address");
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("Internet-Task", "Connected to "server address"");
}
}).on("song add", new Emitter.Listener() {
#Override
public void call(Object... args) {
try {
suggestionSongs.add(new JSONObject(args[0].toString()));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
//**//
socket.io().on(Manager.EVENT_TRANSPORT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Transport transport = (Transport) args[0];
transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() {
#Override
public void call(Object... args) {
#SuppressWarnings("unchecked")
Map<String, List<String>> headers = (Map<String, List<String>>) args[0];
// modify request headers
headers.put("userid", Arrays.asList(userID));
headers.put("roomid", Arrays.asList(roomID));
}
});
socket.connect();
} catch (URISyntaxException e) {
Log.e(getClass().getCanonicalName(), e.toString());
}
Additionally, here is the call to the service made in the Activity onCreate(). No new thread is made prior.
protected void onCreate(Bundle savedInstanceState) {
...
Intent serviceIntent = new Intent(getBaseContext(), SocketService.class);
Bundle serviceBundle = new Bundle();
serviceBundle.putString("code", roomID);;
serviceBundle.putString("userid", userID);
serviceIntent.putExtras(mBundle);
startService(serviceIntent);
Again, my question is: How do I transfer data from my SocketService to the UI of my Activity?
I am basically trying to send a message from my android to my server and the server to send back a response to my android app. I followed THIS tutorial.
Just a simple exercise to introduce myself in to SignalR using Azure Web API and Android.
My Complete Server code in C#:
public class TestHub: Hub {
public void SendMessage(string name, string message) {
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
}
public void SendClientMessage(CustomType obj) {
Clients.All.broadcastMessage("From Server", "Server got the message bro");
}
public class CustomType {
public string Name;
public int Id;
}
}
Complete Android Java code:
public class MainActivity extends AppCompatActivity {
Handler handler;
TextView statustext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
statustext = (TextView) findViewById(R.id.status);
Platform.loadPlatformComponent(new AndroidPlatformComponent());
// Change to the IP address and matching port of your SignalR server.
String host = "https://My-Service-name.azure-mobile.net/";
HubConnection connection = new HubConnection(host);
HubProxy hub = connection.createHubProxy("TestHub");
SignalRFuture < Void > awaitConnection = connection.start();
try {
awaitConnection.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
hub.subscribe(this);
try {
hub.invoke("SendMessage", "Client", "Hello Server!").get();
hub.invoke("SendClientMessage",
new CustomType() {
{
Name = "Android Homie";
Id = 42;
}
}).get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
}
//I have no idea what the following method is for. Just followed the tutorial.. (blindly)
public void UpdateStatus(String status) {
final String fStatus = status;
handler.post(new Runnable() {
#Override
public void run() {
statustext.setText(fStatus);
}
});
}
public class CustomType {
public String Name;
public int Id;
}
}
Problems with this:
1. I get an exception:
java.util.concurrent.ExecutionException:
microsoft.aspnet.signalr.client.transport.NegotiationException: There
was a problem in the negotiation with the server
2. I feel like I haven't properly called the server from the Java code.
Should the URL be:
https://My-Service-name.azure-mobile.net/
or
https://My-Service-name.azure-mobile.net/api/signalr
Can someone clarify these doubts and help me set it up?