4 package org
.netxms
.ui
.android
.main
.activities
;
6 import java
.util
.ArrayList
;
7 import java
.util
.Iterator
;
9 import java
.util
.Stack
;
11 import org
.netxms
.base
.GeoLocation
;
12 import org
.netxms
.client
.NXCSession
;
13 import org
.netxms
.client
.constants
.NodePoller
;
14 import org
.netxms
.client
.objects
.AbstractObject
;
15 import org
.netxms
.client
.objects
.GenericObject
;
16 import org
.netxms
.client
.objects
.Node
;
17 import org
.netxms
.client
.objecttools
.ObjectTool
;
18 import org
.netxms
.ui
.android
.NXApplication
;
19 import org
.netxms
.ui
.android
.R
;
20 import org
.netxms
.ui
.android
.main
.adapters
.ObjectListAdapter
;
21 import org
.netxms
.ui
.android
.main
.fragments
.AlarmBrowserFragment
;
22 import org
.netxms
.ui
.android
.main
.fragments
.NodeInfoFragment
;
24 import android
.app
.AlertDialog
;
25 import android
.app
.ProgressDialog
;
26 import android
.content
.ActivityNotFoundException
;
27 import android
.content
.ComponentName
;
28 import android
.content
.DialogInterface
;
29 import android
.content
.DialogInterface
.OnClickListener
;
30 import android
.content
.Intent
;
31 import android
.net
.Uri
;
32 import android
.os
.AsyncTask
;
33 import android
.os
.Bundle
;
34 import android
.os
.IBinder
;
35 import android
.util
.Log
;
36 import android
.view
.ContextMenu
;
37 import android
.view
.ContextMenu
.ContextMenuInfo
;
38 import android
.view
.Menu
;
39 import android
.view
.MenuItem
;
40 import android
.view
.View
;
41 import android
.widget
.AdapterView
;
42 import android
.widget
.AdapterView
.AdapterContextMenuInfo
;
43 import android
.widget
.ListView
;
44 import android
.widget
.TextView
;
45 import android
.widget
.Toast
;
50 * @author Victor Kirhenshtein
51 * @author Marco Incalcaterra (marco.incalcaterra@thinksoft.it)
55 public class NodeBrowser
extends AbstractClientActivity
57 private static final String TAG
= "nxclient/NodeBrowser";
58 private ListView listView
;
59 private ObjectListAdapter adapter
;
60 private long initialParent
;
61 private AbstractObject currentParent
= null;
62 private final Stack
<AbstractObject
> containerPath
= new Stack
<AbstractObject
>();
63 private long[] savedPath
= null;
64 private AbstractObject selectedObject
= null;
65 private ProgressDialog dialog
;
68 * @see org.netxms.ui.android.main.activities.AbstractClientActivity#onCreateStep2(android.os.Bundle)
71 protected void onCreateStep2(Bundle savedInstanceState
)
73 dialog
= new ProgressDialog(this);
74 setContentView(R
.layout
.node_view
);
76 TextView title
= (TextView
)findViewById(R
.id
.ScreenTitlePrimary
);
77 title
.setText(R
.string
.nodes_title
);
79 initialParent
= getIntent().getIntExtra("parentId", GenericObject
.SERVICEROOT
);
81 // keeps current list of nodes as datasource for listview
82 adapter
= new ObjectListAdapter(this);
84 listView
= (ListView
)findViewById(R
.id
.NodeList
);
85 listView
.setAdapter(adapter
);
86 listView
.setOnItemClickListener(new AdapterView
.OnItemClickListener() {
88 @SuppressWarnings("rawtypes")
89 public void onItemClick(AdapterView parent
, View v
, int position
, long id
)
91 AbstractObject obj
= (AbstractObject
)adapter
.getItem(position
);
92 if ((obj
.getObjectClass() == AbstractObject
.OBJECT_CONTAINER
) ||
93 (obj
.getObjectClass() == AbstractObject
.OBJECT_SUBNET
) ||
94 (obj
.getObjectClass() == AbstractObject
.OBJECT_CLUSTER
) ||
95 (obj
.getObjectClass() == AbstractObject
.OBJECT_ZONE
))
97 containerPath
.push(currentParent
);
101 else if (obj
.getObjectClass() == AbstractObject
.OBJECT_NODE
|| obj
.getObjectClass() == AbstractObject
.OBJECT_MOBILEDEVICE
)
103 showNodeInfo(obj
.getObjectId());
108 registerForContextMenu(listView
);
110 // Restore saved state
111 if (savedInstanceState
!= null)
112 savedPath
= savedInstanceState
.getLongArray("currentPath");
116 * @see android.app.Activity#onSaveInstanceState(android.os.Bundle)
119 protected void onSaveInstanceState(Bundle outState
)
121 savedPath
= getFullPathAsId();
122 outState
.putLongArray("currentPath", savedPath
);
123 super.onSaveInstanceState(outState
);
127 * @see android.app.Activity#onResume()
130 protected void onResume()
133 NXApplication
.activityResumed();
136 service
.reconnect(false);
144 public void showNodeInfo(long objectId
)
146 Intent newIntent
= new Intent(this, NodeInfoFragment
.class);
147 newIntent
.putExtra("objectId", objectId
);
148 startActivity(newIntent
);
154 * @see android.content.ServiceConnection#onServiceConnected(android.content.
155 * ComponentName, android.os.IBinder)
158 public void onServiceConnected(ComponentName name
, IBinder binder
)
160 super.onServiceConnected(name
, binder
);
162 service
.registerNodeBrowser(this);
167 * @see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)
170 public void onCreateContextMenu(ContextMenu menu
, View v
, ContextMenuInfo menuInfo
)
172 android
.view
.MenuInflater inflater
= getMenuInflater();
173 inflater
.inflate(R
.menu
.node_actions
, menu
);
175 AdapterView
.AdapterContextMenuInfo info
= (AdapterContextMenuInfo
)menuInfo
;
176 selectedObject
= (AbstractObject
)adapter
.getItem(info
.position
);
178 GeoLocation gl
= selectedObject
.getGeolocation();
179 if ((gl
== null) || (gl
.getType() == GeoLocation
.UNSET
))
181 hideMenuItem(menu
, R
.id
.navigate_to
);
184 if (selectedObject
instanceof Node
)
186 // add available tools to context menu
187 List
<ObjectTool
> tools
= service
.getTools();
190 Iterator
<ObjectTool
> tl
= tools
.iterator();
195 if ((tool
.getType() == ObjectTool
.TYPE_ACTION
|| tool
.getType() == ObjectTool
.TYPE_SERVER_COMMAND
) &&
196 tool
.isApplicableForNode((Node
)selectedObject
))
198 menu
.add(Menu
.NONE
, (int)tool
.getId(), 0, tool
.getDisplayName());
205 hideMenuItem(menu
, R
.id
.find_switch_port
);
206 hideMenuItem(menu
, R
.id
.poll
);
214 private void hideMenuItem(ContextMenu menu
, int id
)
216 MenuItem item
= menu
.findItem(id
);
218 item
.setVisible(false);
222 * @see android.app.Activity#onContextItemSelected(android.view.MenuItem)
225 public boolean onContextItemSelected(MenuItem item
)
227 if (selectedObject
== null)
228 return super.onContextItemSelected(item
);
230 switch(item
.getItemId())
232 case R
.id
.find_switch_port
:
233 Intent fspIntent
= new Intent(this, ConnectionPointBrowser
.class);
234 fspIntent
.putExtra("nodeId", (int)selectedObject
.getObjectId());
235 startActivity(fspIntent
);
237 case R
.id
.view_alarms
:
238 new SyncMissingChildsTask().execute(new Integer
[] { (int)selectedObject
.getObjectId() });
241 service
.setObjectMgmtState(selectedObject
.getObjectId(), false);
245 service
.setObjectMgmtState(selectedObject
.getObjectId(), true);
248 case R
.id
.poll_status
:
249 Intent psIntent
= new Intent(this, NodePollerActivity
.class);
250 psIntent
.putExtra("nodeId", (int)selectedObject
.getObjectId());
251 psIntent
.putExtra("pollType", NodePoller
.STATUS_POLL
);
252 startActivity(psIntent
);
254 case R
.id
.poll_configuration
:
255 Intent pcIntent
= new Intent(this, NodePollerActivity
.class);
256 pcIntent
.putExtra("nodeId", (int)selectedObject
.getObjectId());
257 pcIntent
.putExtra("pollType", NodePoller
.CONFIGURATION_POLL
);
258 startActivity(pcIntent
);
260 case R
.id
.poll_topology
:
261 Intent ptIntent
= new Intent(this, NodePollerActivity
.class);
262 ptIntent
.putExtra("nodeId", (int)selectedObject
.getObjectId());
263 ptIntent
.putExtra("pollType", NodePoller
.TOPOLOGY_POLL
);
264 startActivity(ptIntent
);
266 case R
.id
.poll_interfaces
:
267 Intent piIntent
= new Intent(this, NodePollerActivity
.class);
268 piIntent
.putExtra("nodeId", (int)selectedObject
.getObjectId());
269 piIntent
.putExtra("pollType", NodePoller
.INTERFACE_POLL
);
270 startActivity(piIntent
);
272 case R
.id
.navigate_to
:
273 GeoLocation gl
= selectedObject
.getGeolocation();
274 Intent intent
= new Intent(Intent
.ACTION_VIEW
, Uri
.parse("google.navigation:q=" + gl
.getLatitude() + ","
275 + gl
.getLongitude()));
276 intent
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
);
279 startActivity(intent
);
281 catch(ActivityNotFoundException e
)
283 Toast
.makeText(getApplicationContext(), "Navigation unavailable", Toast
.LENGTH_LONG
);
287 // if we didn't match static menu, check if it was some of tools
288 List
<ObjectTool
> tools
= service
.getTools();
291 for (final ObjectTool tool
: tools
)
293 if ((int)tool
.getId() == item
.getItemId())
295 if ((tool
.getFlags() & ObjectTool
.ASK_CONFIRMATION
) != 0)
297 String message
= tool
.getConfirmationText()
298 .replaceAll("%OBJECT_NAME%", selectedObject
.getObjectName())
299 .replaceAll("%OBJECT_IP_ADDR%", selectedObject
.getPrimaryIP().getHostAddress());
300 new AlertDialog
.Builder(this)
301 .setIcon(android
.R
.drawable
.ic_dialog_alert
)
302 .setTitle(R
.string
.confirm_tool_execution
)
305 .setPositiveButton(R
.string
.yes
, new OnClickListener()
308 public void onClick(DialogInterface dialog
, int which
)
310 service
.executeAction(selectedObject
.getObjectId(), tool
.getData());
313 .setNegativeButton(R
.string
.no
, null)
317 service
.executeAction(selectedObject
.getObjectId(), tool
.getData());
325 return super.onContextItemSelected(item
);
329 * @see android.app.Activity#onBackPressed()
332 public void onBackPressed()
334 if (this.currentParent
== null)
336 super.onBackPressed();
339 if (this.currentParent
.getObjectId() == this.initialParent
)
341 super.onBackPressed();
344 if (containerPath
.empty())
346 super.onBackPressed();
350 this.currentParent
= containerPath
.pop();
356 * Refresh node list, force reload from server
358 public void refreshList()
360 if (currentParent
== null)
362 currentParent
= service
.findObjectById(initialParent
);
364 if (currentParent
== null)
366 // if still null - problem with root node, stop loading
370 TextView curPath
= (TextView
)findViewById(R
.id
.ScreenTitleSecondary
);
371 curPath
.setText(getFullPath());
372 new SyncMissingObjectsTask(currentParent
.getObjectId()).execute(new Object
[] { currentParent
.getChildIdList() });
378 private void rescanSavedPath()
380 // Restore to saved path if available
381 if ((savedPath
!= null) && (savedPath
.length
> 0))
383 containerPath
.clear();
384 for (int i
= 0; i
< savedPath
.length
- 1; i
++)
386 AbstractObject object
= service
.findObjectById(savedPath
[i
]);
389 containerPath
.push(object
);
390 Log
.i(TAG
, "object.getObjectId(): " + object
.getObjectId());
392 currentParent
= service
.findObjectById(savedPath
[savedPath
.length
- 1]);
399 * Get full path to current position in object tree
403 private String
getFullPath()
405 StringBuilder sb
= new StringBuilder();
406 for (AbstractObject o
: containerPath
)
409 sb
.append(o
.getObjectName());
411 if (currentParent
!= null)
414 sb
.append(currentParent
.getObjectName());
416 return sb
.toString();
420 * Get full path to current position in object tree, as object identifiers
424 private long[] getFullPathAsId()
426 long[] path
= new long[containerPath
.size() + ((currentParent
!= null) ?
1 : 0)];
428 for (AbstractObject o
: containerPath
)
429 path
[i
++] = o
.getObjectId();
431 if (currentParent
!= null)
432 path
[i
++] = currentParent
.getObjectId();
440 * @see android.app.Activity#onDestroy()
443 protected void onDestroy()
445 service
.registerNodeBrowser(null);
450 * Update node list, force refresh as necessary
452 public void updateNodeList()
456 if (currentParent
!= null)
458 AbstractObject
[] list
= currentParent
.getChildsAsArray();
461 adapter
.setNodes(list
);
462 adapter
.notifyDataSetChanged();
473 private void viewAlarms(ArrayList
<Integer
> nodeIdList
)
475 Intent newIntent
= new Intent(this, AlarmBrowserFragment
.class);
476 newIntent
.putIntegerArrayListExtra("nodeIdList", nodeIdList
);
477 startActivity(newIntent
);
481 * Internal task for synching missing objects
483 private class SyncMissingObjectsTask
extends AsyncTask
<Object
, Void
, AbstractObject
[]>
485 private final long currentRoot
;
487 protected SyncMissingObjectsTask(long currentRoot
)
489 this.currentRoot
= currentRoot
;
493 protected void onPreExecute()
495 dialog
.setMessage(getString(R
.string
.progress_gathering_data
));
496 dialog
.setIndeterminate(true);
497 dialog
.setCancelable(false);
502 protected AbstractObject
[] doInBackground(Object
... params
)
506 service
.getSession().syncMissingObjects((long[])params
[0], false, NXCSession
.OBJECT_SYNC_WAIT
);
507 return currentParent
.getChildsAsArray();
511 Log
.e(TAG
, "Exception while executing service.getSession().syncMissingObjects in SyncMissingObjectsTask", e
);
517 protected void onPostExecute(AbstractObject
[] result
)
520 if ((result
!= null) && (currentParent
.getObjectId() == currentRoot
))
522 adapter
.setNodes(result
);
523 adapter
.notifyDataSetChanged();
529 * Internal task for synching missing objects
531 private class SyncMissingChildsTask
extends AsyncTask
<Integer
, Void
, Integer
>
533 private final ArrayList
<Integer
> childIdList
;
535 protected SyncMissingChildsTask()
537 childIdList
= new ArrayList
<Integer
>();
541 protected void onPreExecute()
543 dialog
.setMessage(getString(R
.string
.progress_gathering_data
));
544 dialog
.setIndeterminate(true);
545 dialog
.setCancelable(false);
549 protected void getChildsList(long[] list
)
551 for (int i
= 0; i
< list
.length
; i
++)
553 childIdList
.add((int)list
[i
]);
554 AbstractObject obj
= service
.findObjectById(list
[i
]);
555 if (obj
!= null && (obj
.getObjectClass() == AbstractObject
.OBJECT_CONTAINER
||
556 obj
.getObjectClass() == AbstractObject
.OBJECT_CLUSTER
))
560 service
.getSession().syncMissingObjects(obj
.getChildIdList(), false, NXCSession
.OBJECT_SYNC_WAIT
);
561 getChildsList(obj
.getChildIdList());
565 Log
.e(TAG
, "Exception while executing service.getSession().syncMissingObjects in SyncMissingChildsTask", e
);
572 protected Integer
doInBackground(Integer
... params
)
574 long[] list
= new long[params
.length
];
575 for (int i
= 0; i
< params
.length
; i
++)
576 list
[i
] = params
[i
].longValue();
582 protected void onPostExecute(Integer result
)
585 viewAlarms(childIdList
);