/*******************************************************************************
* Copyright 2016 Specure GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package at.alladin.rmbt.android.loopmode;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import at.alladin.openrmbt.android.R;
import at.alladin.rmbt.android.loopmode.LoopModeResults.Status;
import at.alladin.rmbt.android.loopmode.info.AdditionalInfoFragment;
import at.alladin.rmbt.android.loopmode.info.DetailsInfoListAdapter;
import at.alladin.rmbt.android.loopmode.info.LoopModeTriggerItem;
import at.alladin.rmbt.android.loopmode.info.LoopModeTriggerItem.TriggerType;
import at.alladin.rmbt.android.loopmode.info.TrafficUsageItem;
import at.alladin.rmbt.android.loopmode.measurement.IpAddressItem;
import at.alladin.rmbt.android.loopmode.measurement.MeasurementDetailsFragment;
import at.alladin.rmbt.android.loopmode.measurement.ServerNameItem;
import at.alladin.rmbt.android.main.RMBTMainActivity;
import at.alladin.rmbt.android.test.RMBTLoopService;
import at.alladin.rmbt.android.test.RMBTLoopService.RMBTLoopBinder;
import at.alladin.rmbt.android.test.RMBTLoopService.RMBTLoopServiceConnection;
import at.alladin.rmbt.android.test.RMBTService;
import at.alladin.rmbt.android.test.RMBTService.RMBTBinder;
import at.alladin.rmbt.android.test.RMBTTestFragment;
import at.alladin.rmbt.android.util.InformationCollector;
import at.alladin.rmbt.client.helper.IntermediateResult;
public class LoopModeTestFragment extends Fragment implements ServiceConnection, RMBTLoopServiceConnection {
public final static String TAG = "LoopModeStartFragment";
public static final class LoopModeViewHolder {
private class StringsHolder {
String testRunningString;
String loopModeString;
String waiting;
String finished;
}
DetailsInfoListAdapter unimportantListAdapter;
TextView counterText;
TextView lastTestText;
MeasurementDetailsFragment measurementFragment;
AdditionalInfoFragment infoFragment;
ProgressBar progressBar;
TextView progressText;
ListView unimportantInfoList;
Button cancelButton;
final StringsHolder strings = new StringsHolder();
}
private class RMBTServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
final RMBTBinder binder = (RMBTBinder) service;
Log.d(TAG, "connect RMBT Service");
rmbtService = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "disconnect RMBT Service");
rmbtService = null;
}
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (RMBTService.BROADCAST_TEST_FINISHED.equals(intent.getAction())) {
}
}
};
Handler handler;
RMBTLoopService loopService;
RMBTService rmbtService;
RMBTServiceConnection rmbtServiceConnection = new RMBTServiceConnection();
LoopModeViewHolder holder;
IntermediateResult intermediateResult;
InformationCollector infoCollector;
@Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
handler = new Handler();
infoCollector = new InformationCollector(getActivity(), false, false);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.loop_mode_test_fragment, container, false);
holder = new LoopModeViewHolder();
holder.counterText = (TextView) v.findViewById(R.id.loop_test_counter);
holder.lastTestText = (TextView) v.findViewById(R.id.loop_test_last_test_status);
holder.progressBar = (ProgressBar) v.findViewById(R.id.loop_test_progress_bar);
holder.progressText = (TextView) v.findViewById(R.id.loop_test_progress_bar_text);
holder.unimportantInfoList = (ListView) v.findViewById(R.id.loop_test_unimportant_info_list);
holder.cancelButton = (Button) v.findViewById(R.id.loop_test_close_button);
holder.cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
holder.strings.testRunningString = getResources().getString(R.string.loop_test_progress_test_running);
holder.strings.loopModeString = getResources().getString(R.string.loop_test_progress_test_not_running);
holder.strings.waiting = getResources().getString(R.string.loop_test_progress_test_waiting);
holder.strings.finished = getResources().getString(R.string.loop_test_progress_test_finished);
holder.infoFragment = AdditionalInfoFragment.newInstance();
getChildFragmentManager().beginTransaction().add(R.id.loop_test_details_holder,
holder.infoFragment, "lm_additional_info").commit();
holder.measurementFragment = MeasurementDetailsFragment.newInstance();
getChildFragmentManager().beginTransaction().add(R.id.loop_test_measurement_holder,
holder.measurementFragment, "lm_measurement").commit();
return v;
}
@Override
public void onStop()
{
super.onStop();
handler.removeCallbacks(updateTask);
getActivity().unregisterReceiver(receiver);
getActivity().unbindService(this);
getActivity().unbindService(rmbtServiceConnection);
Log.d(TAG, "UNBIND LOOP MODE SERVICES");
getActivity().getActionBar().show();
((RMBTMainActivity) getActivity()).setLockNavigationDrawer(false);
//getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
if (infoCollector != null) {
infoCollector.unload();
}
}
@Override
public void onStart()
{
super.onStart();
if (infoCollector != null) {
infoCollector.init();
}
getActivity().getActionBar().hide();
((RMBTMainActivity) getActivity()).setLockNavigationDrawer(true);
// Bind to RMBTLoopService
final Intent loopServiceIntent = new Intent(getActivity(), RMBTLoopService.class);
getActivity().bindService(loopServiceIntent, this, 0);
final Intent rmbtServiceIntent = new Intent(getActivity(), RMBTService.class);
getActivity().bindService(rmbtServiceIntent, rmbtServiceConnection, Context.BIND_AUTO_CREATE);
final IntentFilter actionFilter = new IntentFilter(RMBTService.BROADCAST_TEST_FINISHED);
getActivity().registerReceiver(receiver, actionFilter);
Log.d(TAG, "BIND LOOP MODE SERVICES");
handler.post(updateTask);
//getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
@Override
public void onServiceConnected(final ComponentName name, final IBinder service)
{
Log.d(TAG, "loopService connected");
final RMBTLoopBinder binder = (RMBTLoopBinder) service;
loopService = binder.getService();
}
@Override
public void onServiceDisconnected(final ComponentName name)
{
Log.d(TAG, "loopService disconnected");
loopService = null;
}
public final Runnable updateTask = new Runnable() {
@Override
public void run() {
updateUi();
handler.postDelayed(updateTask, 250);
}
};
public void updateUi() {
if (holder != null && loopService != null) {
LoopModeResults loopModeResults = loopService.getLoopModeResults();
holder.counterText.setText(holder.strings.loopModeString + ": "
+ loopModeResults.getNumberOfTests() + "/" + loopModeResults.getMaxTests()
+ (Status.RUNNING.equals(loopModeResults.getStatus()) ? "" : " ("
+ (loopService.isActive() ? holder.strings.waiting : holder.strings.finished) + ")"));
if (Status.RUNNING.equals(loopModeResults.getStatus())) {
loopModeResults = loopService.updateLoopModeResults(true);
if (holder.lastTestText.getVisibility() == View.VISIBLE) {
//loop mode just switched from idle/waiting state to test mode
holder.lastTestText.setVisibility(View.GONE);
holder.unimportantListAdapter = null;
}
if (holder.progressBar.getVisibility() == View.GONE) {
holder.progressBar.setVisibility(View.VISIBLE);
holder.progressText.setVisibility(View.VISIBLE);
}
}
else {
if (holder.lastTestText.getVisibility() != View.VISIBLE) {
//loop mode just switched from test mode to idle/waiting state
holder.unimportantListAdapter = null;
holder.lastTestText.setVisibility(View.VISIBLE);
}
if (holder.progressBar.getVisibility() == View.VISIBLE) {
holder.progressBar.setVisibility(View.GONE);
holder.progressText.setVisibility(View.GONE);
}
}
//update or initialize the "not so important list" (reason why it's at the bottom of the view)
if (holder.unimportantListAdapter != null) {
holder.unimportantListAdapter.notifyDataSetChanged();
}
else {
//different "not so important lists", depending on current test status (running/idle)
if (Status.RUNNING.equals(loopModeResults.getStatus())) {
//during test mode, show current test server and client's ip
final List<DetailsListItem> list = new ArrayList<DetailsListItem>();
list.add(new ServerNameItem(getActivity(), loopModeResults));
list.add(new IpAddressItem(getActivity(), loopModeResults));
holder.unimportantListAdapter = new DetailsInfoListAdapter(getActivity(), list);
holder.unimportantInfoList.setAdapter(holder.unimportantListAdapter);
}
else {
//during idle mode, show current data usage, and both loop mode trigger statuses
final List<DetailsListItem> list = new ArrayList<DetailsListItem>();
list.add(new TrafficUsageItem(getActivity(), loopModeResults));
list.add(new LoopModeTriggerItem(getActivity(), loopModeResults, TriggerType.MOVEMENT));
list.add(new LoopModeTriggerItem(getActivity(), loopModeResults, TriggerType.TIME));
holder.unimportantListAdapter = new DetailsInfoListAdapter(getActivity(), list);
holder.unimportantInfoList.setAdapter(holder.unimportantListAdapter);
}
}
//update last test status
if (holder.lastTestText != null && holder.lastTestText.getVisibility() == View.VISIBLE) {
String lastTestResult = "";
if (loopModeResults != null && loopModeResults.getLastTestResults() != null) {
final Date d = new Date(loopModeResults.getLastTestResults().getLocalStartTimeStamp());
final DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault());
switch (loopModeResults.getLastTestResults().getStatus()) {
case OK:
lastTestResult = getString(R.string.loop_test_last_status_ok);
break;
case REJECTED:
lastTestResult = getString(R.string.loop_test_last_status_rejected);
break;
default:
lastTestResult = getString(R.string.loop_test_last_status_error);
}
lastTestResult += " (" + df.format(d) + ")";
}
holder.lastTestText.setText(lastTestResult);
}
//update measurement list (up/down/ping/qos: last/current test + median values)
if (holder.measurementFragment != null) {
if (!holder.measurementFragment.hasResults()) {
holder.measurementFragment.initList(loopService.getLoopModeResults());
}
else {
holder.measurementFragment.updateList();
}
}
//update info list (location, network, etc...)
if (holder.infoFragment != null) {
if (!holder.infoFragment.hasResults()) {
holder.infoFragment.initList(infoCollector);
}
else {
holder.infoFragment.updateList();
}
}
//loop service is active (= at least one test still has to be run or finished)
if (loopService.isActive()) {
int progress = 0;
String progressText = "";
int maxProgress = 100;
if (rmbtService != null) {
if (Status.RUNNING.equals(loopModeResults.getStatus())) {
//test currently running, test mode:
intermediateResult = rmbtService.getIntermediateResult(intermediateResult);
if (intermediateResult != null) {
progress = (int) (RMBTTestFragment.calculateProgress(intermediateResult, rmbtService.getQoSTestProgress(), rmbtService.getQoSTestSize()) * 100d);
progressText = holder.strings.testRunningString + ": " + progress + "%";
maxProgress = 100;
}
else if (rmbtService.isConnectionError()) {
}
else {
}
}
else {
//no test running, waiting mode:
progress = loopModeResults.getNumberOfTests();
progressText = holder.strings.loopModeString + ": " + loopModeResults.getNumberOfTests() + "/" + loopModeResults.getMaxTests();
maxProgress = loopModeResults.getMaxTests();
}
holder.progressBar.setMax(maxProgress);
holder.progressBar.setProgress(progress);
holder.progressText.setText(progressText);
}
else {
//connecting?
}
}
else {
holder.cancelButton.setText(R.string.loop_test_quit);
}
}
else if (holder != null) {
//service (still) not bound...
}
}
public boolean onBackPressed()
{
if (loopService == null) {
return false;
}
else if (loopService.isRunning() || (loopService.getLoopModeResults().getMaxTests() > loopService.getLoopModeResults().getNumberOfTests())) {
AlertDialog stopDialog = new AlertDialog.Builder(getActivity())
.setTitle(R.string.test_dialog_abort_title)
.setMessage(R.string.loop_mode_test_dialog_abort)
.setPositiveButton(android.R.string.yes, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
stopLoopService();
((RMBTMainActivity)getActivity()).popBackStackFull();
}
})
.setNegativeButton(android.R.string.no, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create();
stopDialog.setCancelable(false);
stopDialog.show();
}
else if (loopService.getLoopModeResults().getMaxTests() <= loopService.getLoopModeResults().getNumberOfTests()) {
//if max tests is reached simply remove this fragment without alert dialog
stopLoopService();
return false;
}
return true;
}
private void stopLoopService() {
if (rmbtService != null) {
rmbtService.stopTest(RMBTService.BROADCAST_TEST_ABORTED);
}
else
{
// to be sure test is stopped:
final Intent service = new Intent(RMBTService.ACTION_ABORT_TEST, null, getActivity(), RMBTService.class);
getActivity().startService(service);
}
((RMBTMainActivity) getActivity()).stopLoopService();
}
@Override
public RMBTLoopService getRMBTLoopService() {
return loopService;
}
}