/*
* Copyright 2013 Liquid Labs Inc.
*
* 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 ca.liquidlabs.android.speedtestvisualizer;
import android.app.Activity;
import android.app.FragmentManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ShareActionProvider;
import android.widget.TextView;
import ca.liquidlabs.android.speedtestvisualizer.activities.AboutAppActivity;
import ca.liquidlabs.android.speedtestvisualizer.activities.DataStatsActivity;
import ca.liquidlabs.android.speedtestvisualizer.activities.MapperActivity;
import ca.liquidlabs.android.speedtestvisualizer.fragments.InputDialogFragment;
import ca.liquidlabs.android.speedtestvisualizer.fragments.InputDialogFragment.InputDialogListener;
import ca.liquidlabs.android.speedtestvisualizer.util.AppConstants;
import ca.liquidlabs.android.speedtestvisualizer.util.AppPackageUtils;
import ca.liquidlabs.android.speedtestvisualizer.util.CsvDataParser;
import ca.liquidlabs.android.speedtestvisualizer.util.Tracer;
import com.google.analytics.tracking.android.EasyTracker;
import com.google.android.gms.common.GooglePlayServicesUtil;
import java.io.FileNotFoundException;
import java.io.InputStream;
/**
* Main entry point launcher activity. Data is loaded here and verified before
* loading maps view.
*/
public class MainActivity extends Activity implements InputDialogListener {
private static final String LOG_TAG = MainActivity.class.getSimpleName();
//
// UI Views Used for this activity
//
private ImageView mIconFeedback;
private TextView mMessageTextView;
private Button mSpeedtestLinkButton;
private Button mRelaunchMapButton;
private Button mLaunchStatsButton;
private LinearLayout mButtonContainer;
// Share action provider for menu item
private ShareActionProvider mShareActionProvider;
/**
* Validated CSV data saved in memory
*/
private static String mLastSessionValidData = null;
private static boolean mIsSharedIntent = false;
/**
* Part of CSV header text, used for data validation
*/
private String mCsvHeaderValidationText = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Tracer.debug(LOG_TAG, "onCreate");
/*
* Get reference to views
*/
mIconFeedback = (ImageView) findViewById(R.id.ic_user_feedback);
mMessageTextView = (TextView) findViewById(R.id.txt_user_feedback_guide);
mSpeedtestLinkButton = (Button) findViewById(R.id.btn_speedtest_app_link);
mRelaunchMapButton = (Button) findViewById(R.id.btn_relaunch_map);
mLaunchStatsButton = (Button) findViewById(R.id.btn_launch_stats);
mButtonContainer = (LinearLayout) findViewById(R.id.button_container);
// Also load the CSV record header text, which is needed to validate
mCsvHeaderValidationText = this.getString(R.string.speedtest_csv_header_validation);
/*
* Get intent, action and MIME type More info/guide:
* http://developer.android.com/training/sharing/receive.html
*/
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
// URI is only available in 3.0
Uri exportFileUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (Intent.ACTION_SEND.equals(action) && type != null) {
mIsSharedIntent = true;
if ("text/plain".equals(type)) {
/*
* Check if this is coming from Speedtest v3.0 app (which has
* attachment file in URI)
*/
if (exportFileUri != null) {
try {
InputStream inputStream = getContentResolver().openInputStream(exportFileUri);
handleIntentText(AppPackageUtils.convertStreamToString(inputStream));
} catch (FileNotFoundException e) {
Log.e(LOG_TAG, "Unable to find file from URI", e);
// unsupported mimetype/data
this.handleInvalidText();
} catch (Exception e) {
Log.e(LOG_TAG, "Unable to handle data.", e);
// unsupported mimetype/data
this.handleInvalidText();
}
} else {
/*
* Fall back to old version implementation
*/
// Handle text being sent
handleIntentText(intent.getStringExtra(Intent.EXTRA_TEXT));
}
} else {
// unsupported mimetype/data
this.handleInvalidText();
}
} else {
// Handle other intents, such as being started from the home screen
}
}
@Override
protected void onStart() {
super.onStart();
Tracer.debug(LOG_TAG, "onStart");
// Tracks activity view using analytics.
EasyTracker.getInstance().activityStart(this);
// Prepare session UI data - based on user input
this.prepareSessionDataUi();
// Prepare button to proper speedtest link
this.prepareSpeedTestLink();
}
@Override
public void onStop() {
super.onStop();
// Tracks activity view using analytics.
EasyTracker.getInstance().activityStop(this);
}
/**
* Handle intent data when shared from speedtest or other app
*
* @param intent Intent received by this activity
*/
private void handleIntentText(String sharedText) {
Tracer.debug(LOG_TAG, "handleIntentText() " + sharedText);
if (CsvDataParser.isValidCsvData(mCsvHeaderValidationText, sharedText)) {
// save the valid data in for current session
mLastSessionValidData = sharedText;
mIsSharedIntent = false;
this.launchDataVisualizerActivity(sharedText, MapperActivity.class);
} else {
this.handleInvalidText();
}
}
/**
* Handle text provided by user from clipboard
*
* @param data User data
*/
private void handleLocalText(String data) {
Tracer.debug(LOG_TAG, "handleLocalText()");
if (CsvDataParser.isValidCsvData(mCsvHeaderValidationText, data)) {
// save the valid data in for current session
mLastSessionValidData = data;
this.launchDataVisualizerActivity(data, MapperActivity.class);
} else {
this.handleInvalidText();
}
}
/**
* Unexpected text is shared/input. Show user feedback.
*/
private void handleInvalidText() {
Tracer.debug(LOG_TAG, "handleInvalidText()");
// give ui feedback with error
mIconFeedback.setImageResource(R.drawable.ic_disappoint);
mMessageTextView.setText(R.string.msg_invalid_data);
mButtonContainer.setVisibility(View.GONE);
}
/**
* Shows input dialog fragment to take input from user
*/
private void showInputDialog() {
FragmentManager fm = getFragmentManager();
InputDialogFragment editNameDialog = InputDialogFragment.newInstance();
editNameDialog.show(fm, "fragment_input_data");
}
/**
* Launches mapping activity when valid CSV data is found.
*
* @param csvData Valid speedtest data
* @param clazz Class activity to launch.
*/
private void launchDataVisualizerActivity(String csvData, Class<?> clazz) {
// Test data ready - go to maps view
Intent intent = new Intent(this, clazz);
intent.putExtra(AppConstants.KEY_SPEEDTEST_CSV_HEADER, mCsvHeaderValidationText);
intent.putExtra(AppConstants.KEY_SPEEDTEST_CSV_DATA, csvData);
startActivity(intent);
// apply slide-in animation
overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
}
/**
* Prepares UI for current session - if user has already imported some data
*/
private void prepareSessionDataUi() {
// if shared intent, UI has been already populated
if (mIsSharedIntent) {
return;
}
if (mLastSessionValidData != null) {
// valid data exist, user already used some data to see maps
mIconFeedback.setImageResource(R.drawable.ic_smile_success);
mMessageTextView.setText(R.string.msg_valid_data_session_available);
mRelaunchMapButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
launchDataVisualizerActivity(mLastSessionValidData, MapperActivity.class);
}
});
mLaunchStatsButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
launchDataVisualizerActivity(mLastSessionValidData, DataStatsActivity.class);
}
});
mButtonContainer.setVisibility(View.VISIBLE);
} else {
// Welcome user and show instructions UI
mIconFeedback.setImageResource(R.drawable.ic_dialog_bubble);
mMessageTextView.setText(R.string.msg_welcome_instructions);
// TODO: Show button with YouTube demo link
mButtonContainer.setVisibility(View.GONE);
}
}
/**
* Prepares speedtest app link button to help user to easily install or
* launch app.
*/
private void prepareSpeedTestLink() {
Tracer.debug(LOG_TAG, "prepareSpeedTestLink()");
if (AppPackageUtils.isSpeedTestAppInstalled(getApplicationContext())) {
// Prepare link to SpeedTest app
mSpeedtestLinkButton.setText(R.string.lbl_launch_speedtest_app);
mSpeedtestLinkButton.setCompoundDrawablesWithIntrinsicBounds(AppPackageUtils
.getAppIcon(getApplicationContext(), AppConstants.PACKAGE_SPEEDTEST_APP), null,
null, null);
// Also setup click listener
mSpeedtestLinkButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(AppPackageUtils.getSpeedTestAppIntent(getApplicationContext()));
}
});
} else {
// Prepare link to SpeedTest app in Google Play
mSpeedtestLinkButton.setText(R.string.lbl_get_app_googleplay);
mSpeedtestLinkButton.setCompoundDrawablesWithIntrinsicBounds(
AppPackageUtils.getAppIcon(getApplicationContext(),
GooglePlayServicesUtil.GOOGLE_PLAY_STORE_PACKAGE),
null, null, null);
// Setup play store intent
mSpeedtestLinkButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri
.parse(AppConstants.PLAY_STORE_BASE_NATIVE_URI
+ AppConstants.PACKAGE_SPEEDTEST_APP)));
}
});
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
// Locate MenuItem with ShareActionProvider
MenuItem item = menu.findItem(R.id.action_share_app);
// Fetch and store ShareActionProvider. More info @
// http://developer.android.com/training/sharing/shareaction.html
mShareActionProvider = (ShareActionProvider) item.getActionProvider();
// Share app using share action provider
if (mShareActionProvider != null) {
mShareActionProvider.setShareIntent(AppPackageUtils.getShareAppIntent(
getApplicationContext()));
}
// Return true to display menu
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_paste_data:
showInputDialog();
return true;
case R.id.action_report_issue:
// Prepare email content and send intent
startActivity(Intent.createChooser(
AppPackageUtils.getReportIssueIntent(getApplicationContext()),
getString(R.string.title_dialog_choose_email)));
return true;
case R.id.action_about_app:
startActivity(new Intent(getApplicationContext(), AboutAppActivity.class));
overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
//
// InputDialogListener implementation
//
/**
* Callback from input dialog fragment with data
*/
@Override
public void onFinishEditDialog(String inputText) {
Tracer.debug(LOG_TAG, "onFinishEditDialog: " + inputText);
this.handleLocalText(inputText);
}
}