I'm looking into a way to tie a running task id into it's corresponding process ID (pid).
The context is a system service which is deployed as part of the platform that needs to monitor the current activity in the foreground, I can use the entire AOSP platform, but I cannot change it.
I have the following code in my service to get the activity stack:
private List<StackInfo> getStack() throws Exception
{
Log.i(TAG, "getStack");
List<StackInfo> stacks = null;
stacks = mAm.getAllStackInfos();
return stacks;
}
and this is the monitoring thread:
private class MonitorThread extends Thread
{
public void run()
{
while (true)
{
try
{
Log.i(TAG, "In MonitorThread");
Thread.sleep(1000);
StackInfo fore = getStack().get(0);
String name = fore.taskNames[fore.taskIds.length-1];
name = name.substring(0, name.indexOf("/"));
/* Next line is where I have the problem, I'm getting the task id (activity id) instead of the PID for the process */
Log.i(TAG, "Current FG PID: "+fore.taskIds[fore.taskIds.length-1] + " name: "+ name + "\n");
}
catch (Exception e)
{
Log.i(TAG, "---=== EXCEPTION!!! ===---");
Log.i(TAG, e.getMessage());
Log.i(TAG, "---=== END EXCEPTION!!! ===---");
}
}
}
}
These achieve the goal of getting the process name that is currently in the foreground by taking the top most activity name from the active stack and trimming the activity name from the result (e.g activity name com.example/MainActivity belongs to process com.example).
So far I have two methods of achieving this, both are far from ideal:
The bad way:
I can iterate every application in the system and look up the current activity in it's activity stack, once a match is found, I can use the application PID (inefficient, O(M) where M is the total number of tasks)
The even worst way
The task names return as com.package.xxx/activity_name where the part preceding the '/' is the process name (as far as I can tell, anyhow). Once I have that, I can call 'ps | grep com.package.xxx' and parse the output for the PID (I really don't want shell calls)
All I can find online is how to get the opposite - all activities that belong to an application.
Anyone has a better idea?
Thanks!
You can get your activity PID by:
int id= android.os.Process.myPid();
To find the PID of Others activities check this link. With ActivityManager you can find all running processes, find the desired activity and then get it's PID...
Related
getConnectionState() as connected /disconnected depending on the device .if it is sending message i should see connected and if it not sending i should get disconnected .But each time i run the below java Program i am getting status as disconnected irrespective of device is sending messages or not
RegistryManager registryManager = RegistryManager.createFromConnectionString(connectionString);
System.out.println(registryManager.getDevices(new Integer(1000)));
while(true){
ArrayList<Device> deviceslist=registryManager.getDevices(new Integer(1000));
for(Device device:deviceslist)
{
/*System.out.println(device.getDeviceId());
System.out.println(device.getPrimaryKey());
System.out.println(device.getSecondaryKey());*/
System.out.println(device.getDeviceId());
System.out.println(device.getConnectionState());
/*System.out.println(device.getConnectionStateUpdatedTime());
System.out.println(device.getLastActivityTime());
System.out.println(device.getStatusReason());
System.out.println(device.getStatusUpdatedTime());
System.out.println(device.getSymmetricKey());
System.out.println(device.geteTag());
*/ }
}
I definitely am seeing otherwise.
I'm creating an simple C# console application using the code below,
static async void QueryDevices()
{
RegistryManager manager = RegistryManager.CreateFromConnectionString(connectionString);
while (true)
{
var devices = await manager.GetDevicesAsync(100);
{
foreach (var item in devices)
{
Console.WriteLine(DateTime.Now + ": " + item.Id + ", " + item.ConnectionState);
System.Threading.Thread.Sleep(100);
}
}
}
}
The git here is to always query the whole device list, because the ConnectionState property somehow looks like "static" memebers of the single device client instance, which is not apt-to change even when the actual state changes.
And my output is like below, the "connected" state is when I'm using an java client sample to send message to the IoT Hub.
reposting this question since I didn't get any responses the first time around. Parse doesn't appear to have any simple means of contacting them about this (which is frustrating), so I really hope someone here can help.
I am currently using Parse to create a messaging app. I have two fundamental ParseObjects in addition to the standard ParseUser, a Chatroom and a Message. A Chatroom contains pointers to the two users in the Chatroom. A Message contains the content of the Message, a pointer to the user who posted it, and a pointer to the Chatroom.
First, I create a list of all the Chatrooms that the current user is in. Then, I'm trying to create a second list of the most recent message in all of these Chatrooms (I have made it impossible to make a Chatroom without sending at least one Message first).
My code looks like this:
TextView mostRecent = (TextView) row.findViewById(R.id.mostRecent);
Date dt1 = null;
ParseQuery lastMessage = ParseQuery.getQuery("Message");
ParseObject chatroom = (ParseObject) roomList.get(position);
Log.w("Chatroom ObjectID...", room.getObjectId());
try {
lastMessage.whereEqualTo("chatroom", chatroom.fetchIfNeeded());
List<ParseObject> allMessages = lastMessage.find();
Log.w("# of Messages...", "Size of the list: " + allMessages.size() + ", Count of query: " + allMessages.count());
if (allMessages.size() > 0) {
mostRecent.setText((String) theList.get(theList.size() - 1).get("content"));
dt1 = allMessages.get(allMessages.size() - 1).getCreatedAt();
}
} catch (ParseException err) {
err.printStackTrace();
Log.w("PARSE ERROR", err.getMessage());
}
This code works for every Chatroom where the current user is the one who created the Chatroom and the Message in that Chatroom. However, whenever I have a different user attempt to start a Chatroom and send a Message to the original user, the code fails.
To be clear, the second user successfully creates both a Chatroom and a Message. I've verified that the Chatroom gets successfully added to the original user's list of Chatrooms, and that the Message contains a pointer to the correct Chatroom. However, for whatever reason, the Logs reveal a list size of 0 and a count of 0. I've even tried querying for the second user's exact message on the original user's account, and it claims the thing doesn't exist.
Any ideas? Could this have something to do with ACL? Thanks in advance!
NOTE: I've confirmed that both users are correctly included in the Message's ACL. What gives? Why isn't this working?
You need to wait for the query to fetch the data.
lastMessage.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> allMessages, ParseException e) {
if (e == null) {
Log.w("# of Messages...", "Size of the list: " + allMessages.size() + ", Count of query: " + allMessages.count());
} else {
Log.w("Exception thrown", e.getMessage());
}
}
}
I am setting up and testing in-app billing. I managed to purchase the android.test.purchased, and it did what it should. But now I need to consume it to continue my testing. The problem is that I can't reach the inventory.
When this is called I get the result.isFaliure() is called and I can't get the inventory.
IabHelper.QueryInventoryFinishedListener _gotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (_iabHelper == null) return;
if (result.isFailure()) {
Log.d(TAG, "Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
_isPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
Log.d(TAG, "User is " + (_isPremium ? "PREMIUM" : "NOT PREMIUM"));
update();
}
};
It logs the error message
Failed to query inventory: IabResult: Error refreshing inventory
(querying owned items). (response: -1003:Purchase signature
verification failed)
The android.test.purchased is still owned - it won't let me buy it again. My phone has network connection so it's not that.
I have NOT uploaded a signed APK to Google Play, does that matter even if I test with googles static ID's?
Solved it...
It seems there are problems with the static purchase ID's.
Here's a sollution I found in THIS thread:
If you have used the android.test.purchased then one way to get rid of the error is to do the following:-
1. Edit Security.java and change the "return false" line in the
verifyPurchase to "return true" - this is temporary, we'll be
putting it back in a minute.
2. In your QueryInventoryFinishedListener, after the "if
(result.isFailure()) {...}" lines add the following to consume and
get rid of your never ending android.test.purchased item:-
if (inventory.hasPurchase(SKU_ANDROID_TEST_PURCHASE_GOOD)) {
mHelper.consumeAsync(inventory.getPurchase(SKU_ANDROID_TEST_PURCHASE_GOOD),null);
}
3. Run your app so the consunmeAsync happens, this gets rid of the
"android.test.purchased" item on the server.
4. Remove the consumeAsync code (or comment it out). Back in the
Security.java, change the "return true" back to "return false".
I found the answer here:
"Here's a recommendation: Make sure that your Billing Key (base64EncodedPublicKey) is properly saved. That was my problem, after all that..."
base64EncodedPublicKey was from another aplication...
It was solution for me.
I'd like to generate alarms on my Java desktop application :
alarms set with a specific date/time which can be in 5 minutes or 5 months
I need to be able to create a SWT application when the alarm is triggered
I need this to be able to work on any OS. The software users will likely have Windows (90% of them), and the rest Mac OS (including me)
the software license must allow me to use it in a commercial program, without requiring to open source it (hence, no GPL)
I cannot require the users to install Cygwin, so the implementation needs to be native to Windows and Unix
I am developing using Java, Eclipse, SWT and my application is deployed from my server using Java Web Start. I'm using Mac OS X.6 for developing.
I think I have a few options:
Run my application at startup, and handle everything myself;
Use a system service.
Use the cron table on Unix, and Scheduled Tasks on Windows
Run at startup
I don't really like this solution, I'm hoping for something more elegant.
Refs: I would like to run my Java program on System Startup on Mac OS/Windows. How can I do this?
System service
If I run it as a system service, I can benefit from this, because the OS will ensure that my software:
is always running
doesn't have/need a GUI
restarts on failure
I've researched some resources that I can use:
run4j — CPL — runs on Windows only, seems like a valid candidate
jsvc — Apache 2.0 — Unix only, seems like a valid candidate
Java Service Wrapper — Various — I cannot afford paid licenses, and the free one is a GPL. Hence, I don't want to/can't use this
My questions in the system service options are:
Are there other options?
Is my planned implementation correct:
at the application startup, check for existence of the service
if it is not installed:
escalate the user to install the service (root on Unix, UAC on Windows)
if the host OS is Windows, use run4j to register the service
if the host OS is Unix, use jsvc to register the service
if it is not running, start it
Thus, at the first run, the application will install the service and start it. When the application closes the service is still running and won't need the application ever again, except if it is unregistered.
However, I think I still miss the "run on startup" feature.
Am I right? Am I missing something?
cron / Task Scheduler
On Unix, I can easily use the cron table without needing the application to escalate the user to root. I don't need to handle restarts, system date changes, etc. Seems nice.
On Windows, I can use the Task Scheduler, even in command-line using At or SchTasks. This seems nice, but I need this to be compatible from XP up to 7, and I can't easily test this.
So what would you do? Did I miss something? Do you have any advice that could help me pick the best and most elegant solution?
Bicou: Great that you shared your solution!
Note that the "schtasks.exe" has some localization issues, if you want to create a daily trigger with it, on an English Windows you'd have to use "daily", on a German one (for example) you'd have to use "täglich" instead.
To resolve this issue I've implemented the call to schtasks.exe with the /xml-option, providing a temporary xml-file which I create by template.
The easiest way to create such a template is to create a task "by hand" and use the "export"-function in the task management GUI tool.
Of the available options you have listed, IMHO Option 3 is better.
As you are looking only for an external trigger to execute the application, CRON or Scheduled tasks are better solutions than other options you have listed. By this way, you remove a complexity from your application and also your application need not be running always. It could be triggered externally and when the execution is over, your application will stop. Hence, unnecessary resource consumption is avoided.
Here's what I ended up implementing:
public class AlarmManager {
public static final String ALARM_CLI_FORMAT = "startalarm:";
public static SupportedOS currentOS = SupportedOS.UNSUPPORTED_OS;
public enum SupportedOS {
UNSUPPORTED_OS,
MAC_OS,
WINDOWS,
}
public AlarmManager() {
final String osName = System.getProperty("os.name");
if (osName == null) {
L.e("Unable to retrieve OS!");
} else if ("Mac OS X".equals(osName)) {
currentOS = SupportedOS.MAC_OS;
} else if (osName.contains("Windows")) {
currentOS = SupportedOS.WINDOWS;
} else {
L.e("Unsupported OS: "+osName);
}
}
/**
* Windows only: name of the scheduled task
*/
private String getAlarmName(final long alarmId) {
return new StringBuilder("My_Alarm_").append(alarmId).toString();
}
/**
* Gets the command line to trigger an alarm
* #param alarmId
* #return
*/
private String getAlarmCommandLine(final long alarmId) {
return new StringBuilder("javaws -open ").append(ALARM_CLI_FORMAT).append(alarmId).append(" ").append(G.JNLP_URL).toString();
}
/**
* Adds an alarm to the system list of scheduled tasks
* #param when
*/
public void createAlarm(final Calendar when) {
// Create alarm
// ... stuff here
final long alarmId = 42;
// Schedule alarm
String[] commandLine;
Process child;
final String alarmCL = getAlarmCommandLine(alarmId);
try {
switch (currentOS) {
case MAC_OS:
final String cron = new SimpleDateFormat("mm HH d M '*' ").format(when.getTime()) + alarmCL;
commandLine = new String[] {
"/bin/sh", "-c",
"crontab -l | (cat; echo \"" + cron + "\") | crontab"
};
child = Runtime.getRuntime().exec(commandLine);
break;
case WINDOWS:
commandLine = new String[] {
"schtasks",
"/Create",
"/ST "+when.get(Calendar.HOUR_OF_DAY) + ":" + when.get(Calendar.MINUTE),
"/SC ONCE",
"/SD "+new SimpleDateFormat("dd/MM/yyyy").format(when.getTime()), // careful with locale here! dd/MM/yyyy or MM/dd/yyyy? I'm French! :)
"/TR \""+alarmCL+"\"",
"/TN \""+getAlarmName(alarmId)+"\"",
"/F",
};
L.d("create command: "+Util.join(commandLine, " "));
child = Runtime.getRuntime().exec(commandLine);
break;
}
} catch (final IOException e) {
L.e("Unable to schedule alarm #"+alarmId, e);
return;
}
L.i("Created alarm #"+alarmId);
}
/**
* Removes an alarm from the system list of scheduled tasks
* #param alarmId
*/
public void removeAlarm(final long alarmId) {
L.i("Removing alarm #"+alarmId);
String[] commandLine;
Process child;
try {
switch (currentOS) {
case MAC_OS:
commandLine = new String[] {
"/bin/sh", "-c",
"crontab -l | (grep -v \""+ALARM_CLI_FORMAT+"\") | crontab"
};
child = Runtime.getRuntime().exec(commandLine);
break;
case WINDOWS:
commandLine = new String[] {
"schtasks",
"/Delete",
"/TN \""+getAlarmName(alarmId)+"\"",
"/F",
};
child = Runtime.getRuntime().exec(commandLine);
break;
}
} catch (final IOException e) {
L.e("Unable to remove alarm #"+alarmId, e);
}
}
public void triggerAlarm(final long alarmId) {
// Do stuff
//...
L.i("Hi! I'm alarm #"+alarmId);
// Remove alarm
removeAlarm(alarmId);
}
}
Usage is simple. Schedule a new alarm using:
final AlarmManager m = new AlarmManager();
final Calendar cal = new GregorianCalendar();
cal.add(Calendar.MINUTE, 1);
m.createAlarm(cal);
Trigger an alarm like this:
public static void main(final String[] args) {
if (args.length >= 2 && args[1] != null && args[1].contains(AlarmManager.ALARM_CLI_FORMAT)) {
try {
final long alarmId = Long.parseLong(args[1].replace(AlarmManager.ALARM_CLI_FORMAT, ""));
final AlarmManager m = new AlarmManager();
m.triggerAlarm(alarmId);
} catch (final NumberFormatException e) {
L.e("Unable to parse alarm !", e);
}
}
}
Tested on Mac OS X.6 and Windows Vista. The class L is an helper to System.out.println and G holds my global constants (here, my JNLP file on my server used to launch my application).
You can also try using Quartz http://quartz-scheduler.org/ . It has a CRON like syntax to schedule jobs.
I believe your scenario is correct. Since services are system specific things, IMHO you should not user a generic package to cover them all, but have a specific mechanism for every system.
I know it's possible to get the local device name as described in the solution to this question Display Android Bluetooth Device Name
What I'm interested in knowing is, can I change the local buetooth name (the one other devices see when I'm in discovery mode) programaticlly. I know you can change it by hand, but I'm writing and app and I want to be able to change the name (add a simple flag) so other devices with the same application can scan and instantly know if the phone is also running the app.
tl;dr: How can I change the bluetooth device name on android?
Yes you can change your device name using setName(String name) of BluetoothAdapter type.Following is the sample code:
private BluetoothAdapter bluetoothAdapter = null;
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
void ChangeDeviceName(){
Log.i(LOG, "localdevicename : "+bluetoothAdapter.getName()+" localdeviceAddress : "+bluetoothAdapter.getAddress());
bluetoothAdapter.setName("NewDeviceName");
Log.i(LOG, "localdevicename : "+bluetoothAdapter.getName()+" localdeviceAddress : "+bluetoothAdapter.getAddress());
}
Thanks for the original answer, here are a few things I found when implementing that might help someone else out.
1) BT has to be enabled for setName() to work.
2) It takes time for BT to Enable. ie. you Can't just call enable() then setName()
3) It takes time for the name to "sink in". ie. you can't call getName() right after setName() and expect the new name.
So, here is a snippet of code I came up with to use a runnable to get the job done in the background. It is also time bound to 10seconds, so it won't run forever if there is a problem.
Finally, this is part of our power on check, and we normally leave BT disabled (due to battery). So, I turn BT back off after, you may not want to do that.
// BT Rename
//
final String sNewName = "Syntactics";
final BluetoothAdapter myBTAdapter = BluetoothAdapter.getDefaultAdapter();
final long lTimeToGiveUp_ms = System.currentTimeMillis() + 10000;
if (myBTAdapter != null)
{
String sOldName = myBTAdapter.getName();
if (sOldName.equalsIgnoreCase(sNewName) == false)
{
final Handler myTimerHandler = new Handler();
myBTAdapter.enable();
myTimerHandler.postDelayed(
new Runnable()
{
#Override
public void run()
{
if (myBTAdapter.isEnabled())
{
myBTAdapter.setName(sNewName);
if (sNewName.equalsIgnoreCase(myBTAdapter.getName()))
{
Log.i(TAG_MODULE, "Updated BT Name to " + myBTAdapter.getName());
myBTAdapter.disable();
}
}
if ((sNewName.equalsIgnoreCase(myBTAdapter.getName()) == false) && (System.currentTimeMillis() < lTimeToGiveUp_ms))
{
myTimerHandler.postDelayed(this, 500);
if (myBTAdapter.isEnabled())
Log.i(TAG_MODULE, "Update BT Name: waiting on BT Enable");
else
Log.i(TAG_MODULE, "Update BT Name: waiting for Name (" + sNewName + ") to set in");
}
}
} , 500);
}
}
To change the bluetooth name properly you need to take care of following things:
1) You need following permissions:
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
2) Check the bluetooth state from adapter as you can only change the name of bluetooth is turned on.
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter.state == BluetoothAdapter.STATE_ON){
bluetoothAdapter.setName("NewDeviceName");
}
3) If the bluetooth is not turned on then you can turn it on with the following command:
bluetoothAdapter.enable()
4) Last thing, please don't use static timers to wait for bluetooth state changes instead the proper way is that you can register for android.bluetooth.adapter.action.STATE_CHANGED broadcast and useBluetoothAdapter.EXTRA_STATE to get the new state of bluetooth whenever it is changed.
Note: Not all devices behave the same when it comes to bluetooth and changing the name due to caching and hw address, so never expect same outcome from all devices.