2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 package com.metis.ccnx.ccnxsdk.metiscontrol;
18 import android.content.Context;
19 import android.content.Intent;
20 import android.os.AsyncTask;
21 import android.os.Bundle;
22 import android.os.Handler;
23 import android.support.design.widget.Snackbar;
24 import android.support.v4.app.Fragment;
25 import android.util.Log;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.AdapterView;
30 import android.widget.CompoundButton;
31 import android.widget.Spinner;
32 import android.widget.Switch;
33 import android.widget.TextView;
35 import com.metis.ccnx.ccnxsupportlibrary.Metis;
37 import org.json.JSONException;
38 import org.json.JSONObject;
40 import java.net.Inet4Address;
41 import java.net.InetAddress;
42 import java.nio.charset.Charset;
43 import java.util.List;
46 public class MetisStatusFragment extends Fragment implements IMetisNamedFragment {
48 private static final String ARG_PAGER_INDEX = "metisstatus_pager_number";
49 private static final String TAG = "CCNXMetis SF";
51 // TODO: Rename and change types of parameters
52 private int mPagerIndex;
54 private Switch mSwitchMetisOnOff = null;
55 private Spinner mSpinnerLogLevel = null;
56 private Switch mSwitchContentStoreOnOff = null;
57 private TextView mTVNumInterests = null;
58 private TextView mTVNumContentObjects = null;
59 private TextView mTVNumInterestReturns = null;
60 private TextView mTVNumControlMessages = null;
61 private TextView mTVNumPITEntries = null;
62 private TextView mPathTextView = null;
64 // Stats counters, updated by background task.
65 private long mNumInterests = 0;
66 private long mNumCOs = 0;
67 private long mNumInterestReturns = 0;
68 private long mNumControl = 0;
69 private long mNumPITENtries = 0;
71 private boolean mIsStatsQueryRunning = false;
74 //private PortalFactory mPortalFactory = null;
76 private OnFragmentVisibleListener mListener;
80 * Create a Handler and a Runnable to be called every few seconds to query
81 * Metis (when running) for stats.
83 private Handler mStatusUpdaterHandler = new Handler();
84 private Runnable mStatusUpdateRunnable = new Runnable() {
87 // This runs on the main thread, so start an AsyncTask
88 // Repeat this the same runnable code block again another few seconds
89 //new GetStatusTask(null).execute(mPortalFactory);
90 //if (mIsStatsQueryRunning) {
91 //mStatusUpdaterHandler.postDelayed(mStatusUpdateRunnable, 2 * 1000);
97 public MetisStatusFragment() {
98 // Required empty public constructor
102 * Use this factory method to create a new instance of
103 * this fragment using the provided parameters.
105 * @return A new instance of fragment MetisStatusFragment.
107 // TODO: Rename and change types and number of parameters
108 public static MetisStatusFragment newInstance(int pagerIndex) {
109 MetisStatusFragment fragment = new MetisStatusFragment();
110 Bundle args = new Bundle();
111 args.putInt(ARG_PAGER_INDEX, pagerIndex);
113 fragment.setArguments(args);
119 public void onStart() {
120 Metis metis = Metis.getInstance();
121 mSwitchMetisOnOff.setChecked(metis.isRunning());
127 public void onCreate(Bundle savedInstanceState) {
128 super.onCreate(savedInstanceState);
129 if (getArguments() != null) {
130 mPagerIndex = getArguments().getInt(ARG_PAGER_INDEX);
134 Log.d(TAG, "Creating new PortalFactory");
135 //Identity identity = CCNxUtils.createCCNxIdentity(getContext(),
136 // "password", "ccnxsdkdemo", 1024, 30);
137 //mPortalFactory = new PortalFactory(identity);
143 public View onCreateView(LayoutInflater inflater, ViewGroup container,
144 Bundle savedInstanceState) {
145 // Inflate the layout for this fragment
146 View view = inflater.inflate(R.layout.fragment_metis_status, container, false);
148 mSwitchMetisOnOff = (Switch) view.findViewById(R.id.switchMetisOnOff);
149 mSwitchContentStoreOnOff = (Switch) view.findViewById(R.id.switchMetisContentStoreOnOff);
150 mSpinnerLogLevel = (Spinner) view.findViewById(R.id.spinnerMetisLoggingLevel);
151 mPathTextView = (TextView) view.findViewById(R.id.pathText) ;
153 mSpinnerLogLevel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
155 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
156 String loggingLevel = mSpinnerLogLevel.getSelectedItem().toString();
157 updateMetisLoggingLevel(loggingLevel);
161 public void onNothingSelected(AdapterView<?> parent) {
166 mSwitchMetisOnOff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
168 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
171 //mSpinnerLogLevel.setEnabled(true);
172 //Log.d(TAG, "################# Start periodic query for stats");
173 //if (!mIsStatsQueryRunning) {
174 // mStatusUpdaterHandler.postDelayed(mStatusUpdateRunnable, 500);
175 // mIsStatsQueryRunning = true;
176 // String loggingLevel = mSpinnerLogLevel.getSelectedItem().toString();
177 // if (!loggingLevel.equalsIgnoreCase("off")) {
178 // updateMetisLoggingLevel(loggingLevel);
182 Log.d(TAG, "################# Stop periodic query for stats");
183 //mStatusUpdaterHandler.removeCallbacks(mStatusUpdateRunnable);
184 //mIsStatsQueryRunning = false;
186 //mSpinnerLogLevel.setEnabled(false);
187 //mSpinnerLogLevel.setSelection(0);
192 mTVNumInterests = (TextView) view.findViewById(R.id.tvStatsNumInterests);
193 mTVNumContentObjects = (TextView) view.findViewById(R.id.tvStatsNumContentObjects);
194 mTVNumInterestReturns = (TextView) view.findViewById(R.id.tvStatsNumInterestReturns);
195 mTVNumControlMessages = (TextView) view.findViewById(R.id.tvStatsNumControl);
196 mTVNumPITEntries = (TextView) view.findViewById(R.id.tvStatsPITSize);
198 mTVNumInterests.setText(String.valueOf(mNumInterests));
199 mTVNumContentObjects.setText(String.valueOf(mNumCOs));
200 mTVNumControlMessages.setText(String.valueOf(mNumControl));
201 mTVNumInterestReturns.setText(String.valueOf(mNumInterestReturns));
202 mTVNumPITEntries.setText("");
207 private void startMetis() {
208 mPathTextView.setEnabled(false);
209 Metis metis = Metis.getInstance();
210 if (!metis.isRunning()) {
211 Intent intent = new Intent(getActivity(), MetisService.class);
212 intent.putExtra("path", mPathTextView.getText());
213 getActivity().startService(intent);
215 new Handler().postDelayed(new Runnable() {
218 createExternalListeners();
224 private void stopMetis() {
225 mPathTextView.setEnabled(true);
226 Intent intent = new Intent(getActivity(), MetisService.class);
228 getActivity().stopService(intent);
232 private void updateMetisLoggingLevel(String loggingLevel) {
233 /*Metis metis = Metis.getInstance();
234 if (metis.isRunning()) {
235 // Send an Interest control message to Metis with the new logging level.
236 String commandURI = MetisConstants.CCNxNameMetisCommand_Set + "/" + MetisConstants.MetisCommand_LogLevel + "/" + loggingLevel;
237 Name name = new Name(commandURI);
238 SendInterestTask task = new SendInterestTask(name, null, new SendInterestTask.OnInterestSentListener() {
240 public void onInterestSent(Message message) {
241 if (message instanceof ContentObject) {
243 String responseString = new String(((ContentObject) message).payload());
244 Snackbar snackbar = Snackbar
245 .make(mSwitchMetisOnOff, responseString, Snackbar.LENGTH_SHORT);
249 Log.d(TAG, "Unexpected non-Content response from sent Interest");
254 task.execute(mPortalFactory);
258 private void createExternalListeners() {
260 /*Metis metis = Metis.getInstance();
262 if (metis.isRunning()) {
264 List<InetAddress> ipAddresses = CCNxUtils.getLocalIpAddress();
266 for (InetAddress addr : ipAddresses) {
268 // For the moment, just listen on the IPV4 addresses. The V6 addresses should work,
269 // but it's not yet tested.
271 if (addr instanceof Inet4Address) {
273 String ipAddress = addr.getHostAddress();
275 Log.d(TAG, "Adding external listener on: " + ipAddress);
277 String linkURI = "tcp://" + ipAddress + ":" + MetisConstants.MetisDefaultListenerPort + "/listener";
279 Name name = new Name(MetisConstants.CCNxNameMetisCommand_LinkConnect);
281 SendInterestTask task = new SendInterestTask(name, linkURI.getBytes(), new SendInterestTask.OnInterestSentListener() {
283 public void onInterestSent(Message message) {
284 if (message instanceof ContentObject) {
286 String responseString = new String(((ContentObject) message).payload());
287 Snackbar snackbar = Snackbar
288 .make(mSwitchMetisOnOff, responseString, Snackbar.LENGTH_SHORT);
292 Log.d(TAG, "Unexpected non-Content response from sent Interest");
297 task.execute(mPortalFactory);
305 public void onAttach(Context context) {
306 super.onAttach(context);
307 if (context instanceof OnFragmentVisibleListener) {
308 mListener = (OnFragmentVisibleListener) context;
310 throw new RuntimeException(context.toString()
311 + " must implement OnFragmentInteractionListener");
317 public void setUserVisibleHint(boolean isVisibleToUser) {
318 super.setUserVisibleHint(isVisibleToUser);
319 Metis metis = Metis.getInstance();
321 if (isVisibleToUser) {
322 mListener.onFragmentVisible(this);
324 if (metis.isRunning()) {
325 // Begin updating stats.
326 if (!mIsStatsQueryRunning) {
327 mStatusUpdaterHandler.postDelayed(mStatusUpdateRunnable, 100);
328 mIsStatsQueryRunning = true;
332 mStatusUpdaterHandler.removeCallbacks(mStatusUpdateRunnable);
333 mIsStatsQueryRunning = false;
338 public void onDetach() {
339 mStatusUpdaterHandler.removeCallbacks(mStatusUpdateRunnable);
340 mIsStatsQueryRunning = false;
346 public String getFragmentName() {
350 public interface OnFragmentVisibleListener {
351 // TODO: Update argument type and name
352 void onFragmentVisible(Fragment which);
355 /*private class GetStatusTask extends AsyncTask<PortalFactory, String, Integer> {
357 private boolean mSuccess = false;
358 private PortalFactory mPortalFactory = null;
361 public GetStatusTask(String unused) {
365 protected Integer doInBackground(PortalFactory... args) {
366 Thread.currentThread().setName("GetStatusTask-Async");
368 mPortalFactory = args[0];
370 Name controlName = new Name(MetisConstants.CCNxNameMetisCommand_Stats);
372 Interest interest = new Interest(controlName);
375 Portal portal = mPortalFactory.getPortal();
377 portal.send(interest, 0L);
379 Message m = portal.receive(0L);
381 if (m instanceof ContentObject) {
383 ContentObject co = (ContentObject) m;
384 byte[] payload = co.payload();
386 if (payload != null) {
387 String jsonString = new String(payload, Charset.defaultCharset());
388 //Log.d(TAG, "Received: XX " + jsonString + " XX");
390 JSONObject jo = new JSONObject(jsonString);
391 //Log.d(TAG, "JSON2: " + jo.toString(2));
393 mNumInterests = jo.getLong("numProcessedInterests");
394 mNumCOs = jo.getLong("numProcessedContentObjects");
395 mNumControl = jo.getLong("numProcessedControlMessages");
396 mNumInterestReturns = jo.getLong("numProcessedInterestReturns");
397 } catch (JSONException ex) {
398 Log.e(TAG, "Could not parse returned JSON: " + ex.getMessage());
403 } catch (Portal.CommunicationsError ex) {
404 Log.e(TAG, "Error sending AddLink command: " + ex.getMessage());
406 } catch (Exception ex) {
407 Log.e(TAG, "Error adding link: " + ex.getMessage());
414 protected void onPostExecute(Integer ignored) {
417 mTVNumInterests.setText(String.valueOf(mNumInterests));
418 mTVNumContentObjects.setText(String.valueOf(mNumCOs));
419 mTVNumControlMessages.setText(String.valueOf(mNumControl));
420 mTVNumInterestReturns.setText(String.valueOf(mNumInterestReturns));
421 mTVNumPITEntries.setText("");