This commit is contained in:
Jimmy Shih
2012-01-19 10:51:07 -08:00
11 changed files with 382 additions and 775 deletions
+1
View File
@@ -249,6 +249,7 @@ limitations under the License.
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity"/>
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity"/>
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.SendFusionTablesActivity"/>
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity"/>
<service android:name="com.google.android.apps.mytracks.services.TrackRecordingService"
android:label="@string/my_tracks_recording_service"
@@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2011 Google 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.
-->
<!--
This layout is used as the content view for the send-to-Google result dialog.
It is used to summarize the results of uploading track data to one or more
services.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:paddingLeft="14dip"
android:paddingRight="14dip"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/send_google_result_header"
style="?android:attr/textAppearanceLarge"/>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<!-- We don't want a divider, so we set its color to transparent. -->
<!-- We do this explicitly, rather than with a color resource, because -->
<!-- an apparent bug causes the divider to be wildly misrendered on -->
<!-- a Mini X10 running 2.1. -->
<ListView
android:id="@+id/send_to_google_result_list"
android:clickable="false"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:divider="#00000000"/>
</TableLayout>
<TextView
android:id="@+id/send_to_google_result_comment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/send_google_success_footer"
android:visibility="gone"
style="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/send_to_google_result_error"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/send_google_error"
android:visibility="gone"
style="?android:attr/textAppearanceLarge"/>
</LinearLayout>
@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2011 Google 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.
-->
<!--
This layout represents the result of sending track data to a single service.
It will be instantiated by a custom ListAdapter - once for each service to
which track data was uploaded.
-->
<TableRow
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/send_to_google_result_icon"
android:src="@drawable/success"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="top"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/send_to_google_result_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Google Docs"
style="?android:attr/textAppearanceMedium"/>
<TextView
android:id="@+id/send_to_google_result_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="http://google.com"
style="?android:attr/textAppearanceSmall"/>
</LinearLayout>
</TableRow>
+143
View File
@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2012 Google 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<ScrollView
android:layout_height="0dp"
android:layout_margin="5dp"
android:layout_weight="1"
android:layout_width="fill_parent">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<!-- Header -->
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/send_google_result_header"
style="?android:attr/textAppearanceLarge"/>
<!-- Google Maps result -->
<LinearLayout
android:id="@+id/upload_result_maps_result"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/upload_result_maps_result_icon"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/success"/>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<TextView
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="@string/send_google_maps"
style="?android:attr/textAppearanceMedium"/>
<TextView
android:id="@+id/upload_result_list_item_url"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="@string/send_google_maps_url"
style="?android:attr/textAppearanceSmall"/>
</LinearLayout>
</LinearLayout>
<!-- Google Fusion Tables result -->
<LinearLayout
android:id="@+id/upload_result_fusion_tables_result"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/upload_result_fusion_tables_result_icon"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/success"/>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<TextView
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="@string/send_google_fusion_tables"
style="?android:attr/textAppearanceMedium"/>
<TextView
android:id="@+id/upload_result_list_item_url"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="@string/send_google_fusion_tables_url"
style="?android:attr/textAppearanceSmall"/>
</LinearLayout>
</LinearLayout>
<!-- Google Docs result -->
<LinearLayout
android:id="@+id/upload_result_docs_result"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/upload_result_docs_result_icon"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/success"/>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<TextView
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="@string/send_google_docs"
style="?android:attr/textAppearanceMedium"/>
<TextView
android:id="@+id/upload_result_list_item_url"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="@string/send_google_docs_url"
style="?android:attr/textAppearanceSmall"/>
</LinearLayout>
</LinearLayout>
<!-- Footer -->
<TextView
android:id="@+id/upload_result_success_footer"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="@string/send_google_success_footer"
style="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/upload_result_error_footer"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="@string/send_google_error"
style="?android:attr/textAppearanceLarge"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
@@ -1,109 +0,0 @@
/*
* Copyright 2011 Google 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 com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.view.View;
import android.widget.ListView;
import java.util.List;
/**
* Creates the dialog used to display the results of sending track data to
* Google. The dialog lists the services to which data was uploaded, along
* with an indicator of success/failure. If possible, a button is displayed
* offering to share the uploaded track.
*
* Implementation note: This class is a factory, rather than a {@link Dialog}
* subclass, because alert dialogs have to be created with
* {@link AlertDialog.Builder}. Attempts to subclass {@link AlertDialog}
* directly have been unsuccessful, as {@link AlertDialog.Builder} uses a
* private subclass to implement most of the interesting behavior.
*
* @author Matthew Simmons
*/
public class ResultDialogFactory {
private ResultDialogFactory() {}
/**
* Create a send-to-Google result dialog. The caller is responsible for
* showing it.
*
* @param activity the activity associated with the dialog
* @param results the results to be displayed in the dialog
* @param onOkClickListener the listener to invoke if the OK button is
* clicked
* @param onShareClickListener the listener to invoke if the Share button is
* clicked. If no share listener is provided, the Share button will not
* be displayed.
* @return the created dialog
*/
public static AlertDialog makeDialog(Activity activity, List<SendResult> results,
DialogInterface.OnClickListener onOkClickListener,
DialogInterface.OnClickListener onShareClickListener,
DialogInterface.OnCancelListener onCancelListener) {
boolean success = true;
for (SendResult result : results) {
if (!result.isSuccess()) {
success = false;
break;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(activity)
.setView(makeDialogContent(activity, results, success));
if (success) {
builder.setTitle(R.string.generic_success_title);
builder.setIcon(android.R.drawable.ic_dialog_info);
} else {
builder.setTitle(R.string.generic_error_title);
builder.setIcon(android.R.drawable.ic_dialog_alert);
}
builder.setPositiveButton(activity.getString(R.string.generic_ok), onOkClickListener);
if (onShareClickListener != null) {
builder.setNegativeButton(activity.getString(R.string.send_google_result_share_url),
onShareClickListener);
}
builder.setOnCancelListener(onCancelListener);
return builder.create();
}
private static View makeDialogContent(Activity activity, List<SendResult> results,
boolean success) {
ResultListAdapter resultListAdapter = new ResultListAdapter(activity,
R.layout.send_to_google_result_list_item, results);
View content = activity.getLayoutInflater().inflate(R.layout.send_to_google_result, null);
ListView resultList = (ListView) content.findViewById(R.id.send_to_google_result_list);
resultList.setAdapter(resultListAdapter);
content.findViewById(R.id.send_to_google_result_comment)
.setVisibility(success ? View.VISIBLE : View.GONE);
content.findViewById(R.id.send_to_google_result_error)
.setVisibility(success ? View.GONE : View.VISIBLE);
return content;
}
}
@@ -1,85 +0,0 @@
/*
* Copyright 2011 Google 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 com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
import java.util.List;
/**
* This class implements the {@link ListAdapter} used by the send-to-Google
* result dialog created by {@link ResultDialogFactory}. It generates views
* for each entry in an array of {@link SendResult} instances.
* @author Matthew Simmons
*/
class ResultListAdapter extends ArrayAdapter<SendResult> {
public ResultListAdapter(Context context, int textViewResourceId, List<SendResult> results) {
super(context, textViewResourceId, results);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater
= (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.send_to_google_result_list_item, null);
}
SendResult result = getItem(position);
setImage(view, result.isSuccess() ? R.drawable.success : R.drawable.failure);
setName(view, result.getType().getServiceName());
setUrl(view, result.getType().getServiceUrl());
return view;
}
@Override
public boolean areAllItemsEnabled() {
// We don't want the displayed items to be clickable
return false;
}
// The following protected methods exist to be overridden for testing
// purposes. Doing so insulates the test class from the details of the
// layout.
protected void setImage(View content, int drawableId) {
ImageView imageView = (ImageView) content.findViewById(R.id.send_to_google_result_icon);
imageView.setImageDrawable(getContext().getResources().getDrawable(drawableId));
}
protected void setName(View content, int nameId) {
setTextViewText(content, R.id.send_to_google_result_name, nameId);
}
protected void setUrl(View content, int urlId) {
setTextViewText(content, R.id.send_to_google_result_url, urlId);
}
private void setTextViewText(View content, int viewId, int textId) {
TextView textView = (TextView) content.findViewById(viewId);
textView.setText(getContext().getString(textId));
}
};
@@ -37,18 +37,11 @@ import android.accounts.Account;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Helper activity for managing the sending of tracks to Google services.
@@ -89,22 +82,16 @@ public class SendActivity extends Activity implements ProgressIndicator {
SEND_TO_DOCS,
SEND_TO_DOCS_DONE,
SHOW_RESULTS,
SHARE_LINK,
FINISH,
DONE,
NOT_READY
}
private static final int PROGRESS_DIALOG = 1;
/* @VisibleForTesting */
static final int DONE_DIALOG = 2;
// UI
private ProgressDialog progressDialog;
// Set in Activity.onCreate
private MyTracksProviderUtils providerUtils;
private SharedPreferences sharedPreferences;
private GoogleAnalyticsTracker tracker;
// Send request information. Set by the intent that starts the activity.
@@ -129,20 +116,17 @@ public class SendActivity extends Activity implements ProgressIndicator {
private String sendToMapsMapId;
private String sendToFusionTablesTableId;
private final OnCancelListener finishOnCancelListener = new OnCancelListener() {
@Override
public void onCancel(DialogInterface arg0) {
onAllDone();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "SendActivity.onCreate");
super.onCreate(savedInstanceState);
if (!handleIntent()) {
finish();
return;
}
providerUtils = MyTracksProviderUtils.Factory.get(this);
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
tracker = GoogleAnalyticsTracker.getInstance();
// Start the tracker in manual dispatch mode...
@@ -162,14 +146,6 @@ public class SendActivity extends Activity implements ProgressIndicator {
resetState();
}
// Only consider the intent if we're not restoring from a previous state.
if (currentState == SendState.CHOOSE_ACCOUNT) {
if (!handleIntent()) {
finish();
return;
}
}
// Execute the state machine, at the start or restored state.
Log.w(TAG, "Starting at state " + currentState);
executeStateMachine(currentState);
@@ -196,8 +172,6 @@ public class SendActivity extends Activity implements ProgressIndicator {
switch (id) {
case PROGRESS_DIALOG:
return createProgressDialog();
case DONE_DIALOG:
return createDoneDialog();
default:
return null;
}
@@ -231,17 +205,10 @@ public class SendActivity extends Activity implements ProgressIndicator {
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "SendActivity.onStop, state=" + currentState);
tracker.dispatch();
tracker.stop();
super.onStop();
}
@Override
protected void onDestroy() {
Log.d(TAG, "SendActivity.onDestroy, state=" + currentState);
super.onDestroy();
}
private void executeStateMachine(SendState startState) {
@@ -285,8 +252,6 @@ public class SendActivity extends Activity implements ProgressIndicator {
return onSendToGoogleDocsDone();
case SHOW_RESULTS:
return onSendToGoogleDone();
case SHARE_LINK:
return shareLink();
case FINISH:
return onAllDone();
default:
@@ -472,145 +437,33 @@ public class SendActivity extends Activity implements ProgressIndicator {
private SendState onSendToGoogleDone() {
tracker.dispatch();
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Sending to Google done.");
removeDialog(PROGRESS_DIALOG);
// Ensure a new done dialog is created each time.
// This is required because the send results must be available at the
// time the dialog is created.
removeDialog(DONE_DIALOG);
showDialog(DONE_DIALOG);
}
});
return SendState.NOT_READY;
String mapsUrl = sendToMaps && sendToMapsSuccess
? MapsFacade.buildMapUrl(sendToMapsMapId)
: null;
Track track = providerUtils.getTrack(sendTrackId);
String fusionTablesUrl = sendToFusionTables && sendToFusionTablesSuccess
? SendFusionTablesUtils.getMapUrl(track)
: null;
Intent intent = new Intent(this, UploadResultActivity.class)
.putExtra(UploadResultActivity.HAS_MAPS_RESULT, sendToMaps)
.putExtra(UploadResultActivity.HAS_FUSION_TABLES_RESULT, sendToFusionTables)
.putExtra(UploadResultActivity.HAS_DOCS_RESULT, sendToDocs)
.putExtra(UploadResultActivity.MAPS_SUCCESS, sendToMapsSuccess)
.putExtra(UploadResultActivity.FUSION_TABLES_SUCCESS, sendToFusionTablesSuccess)
.putExtra(UploadResultActivity.DOCS_SUCCESS, sendToDocsSuccess)
.putExtra(UploadResultActivity.SHARE_REQUEST, shareRequest)
.putExtra(UploadResultActivity.MAPS_URL, mapsUrl)
.putExtra(UploadResultActivity.FUSION_TABLES_URL, fusionTablesUrl);
startActivity(intent);
return SendState.FINISH;
}
private Dialog createDoneDialog() {
Log.d(TAG, "Creating done dialog");
// We've finished sending the track to the user-selected services. Now
// we tell them the results of the upload, and optionally share the track.
// There are a few different paths through this code:
//
// 1. The user pre-requested a share (shareRequested == true). We're going
// to display the result dialog *without* the share button (the share
// listener will be null). The OK button listener will initiate the
// share.
//
// 2. The user did not pre-request a share, and the set of services to
// which we succeeded in uploading the track are compatible with
// sharing. We'll display a share button (the share listener will be
// non-null), and will share the link if the user clicks it.
//
// 3. The user did not pre-request a share, and the set of services to
// which we succeeded in uploading the track are incompatible with
// sharing. We won't display a share button.
List<SendResult> results = makeSendToGoogleResults();
final boolean canShare = sendToFusionTablesTableId != null || sendToMapsMapId != null;
final OnClickListener finishListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
executeStateMachine(SendState.FINISH);
}
};
DialogInterface.OnClickListener doShareListener = null;
if (canShare) {
doShareListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
executeStateMachine(SendState.SHARE_LINK);
}
};
}
DialogInterface.OnClickListener onOkListener = (canShare && shareRequest)
? doShareListener : finishListener;
DialogInterface.OnClickListener onShareListener = (canShare && !shareRequest)
? doShareListener : null;
return ResultDialogFactory.makeDialog(
this, results, onOkListener, onShareListener, finishOnCancelListener);
}
private SendState onAllDone() {
Log.d(TAG, "All sending done.");
removeDialog(PROGRESS_DIALOG);
removeDialog(DONE_DIALOG);
progressDialog = null;
finish();
return SendState.DONE;
}
private SendState shareLink() {
String url = null;
if (sendToMaps && sendToMapsSuccess) {
// Prefer a link to Maps
url = MapsFacade.buildMapUrl(sendToMapsMapId);
} else if (sendToFusionTables && sendToFusionTablesSuccess) {
// Otherwise try using the link to fusion tables
Track track = providerUtils.getTrack(sendTrackId);
url = SendFusionTablesUtils.getMapUrl(track);
}
if (url != null) {
shareLinkToMap(url);
} else {
Log.w(TAG, "Failed to share link");
}
return SendState.FINISH;
}
/**
* Shares a link to a Map or Fusion Table via external app (email, gmail, ...)
* A chooser with apps that support text/plain will be shown to the user.
*/
private void shareLinkToMap(String url) {
boolean shareUrlOnly = sharedPreferences.getBoolean(
getString(R.string.share_url_only_key), false);
String msg = shareUrlOnly ? url : String.format(
getResources().getText(R.string.share_track_url_body_format).toString(), url);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
getResources().getText(R.string.share_track_subject).toString());
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
startActivity(Intent.createChooser(shareIntent,
getResources().getText(R.string.share_track_picker_title).toString()));
}
/**
* Creates a list of {@link SendResult} instances based on the set of
* services selected in {@link SendDialog} and the results as known to
* this class.
*/
private List<SendResult> makeSendToGoogleResults() {
List<SendResult> results = new ArrayList<SendResult>();
if (sendToMaps) {
results.add(new SendResult(SendType.MAPS, sendToMapsSuccess));
}
if (sendToFusionTables) {
results.add(new SendResult(SendType.FUSION_TABLES,
sendToFusionTablesSuccess));
}
if (sendToDocs) {
results.add(new SendResult(SendType.DOCS, sendToDocsSuccess));
}
return results;
}
/**
/**
* Initializes the authentication manager which obtains an authentication
* token, prompting the user for a login and password if needed.
*/
@@ -720,6 +573,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
}
return authManager;
}
/**
* Resets status information for sending to Maps/Fusion Tables/Docs.
*/
@@ -1,46 +0,0 @@
/*
* Copyright 2011 Google 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 com.google.android.apps.mytracks.io.sendtogoogle;
/**
* This class represents the the result of the uploading of track data to a
* single service.
*
* @author Matthew Simmons
*/
public class SendResult {
private final SendType type;
private final boolean success;
/**
* @param type the service to which track data was uploaded
* @param success true if the uploading succeeded
*/
public SendResult(SendType type, boolean success) {
this.type = type;
this.success = success;
}
/** Returns the service to which the track data was uploaded */
public SendType getType() {
return type;
}
/** Returns true if the uploading succeeded */
public boolean isSuccess() {
return success;
}
}
@@ -0,0 +1,210 @@
/*
* Copyright 2012 Google 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 com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* A dialog to show the result of uploading to Google services.
*
* @author jshih@google.com (Jimmy Shih)
*/
public class UploadResultActivity extends Activity {
public static final String HAS_MAPS_RESULT = "hasMapsResult";
public static final String HAS_FUSION_TABLES_RESULT = "hasFusionTablesResult";
public static final String HAS_DOCS_RESULT = "hasDocsResult";
public static final String MAPS_SUCCESS = "mapsSuccess";
public static final String FUSION_TABLES_SUCCESS = "fusionTablesSuccess";
public static final String DOCS_SUCCESS = "docsSuccess";
public static final String SHARE_REQUEST = "shareRequest";
public static final String MAPS_URL = "mapsUrl";
public static final String FUSION_TABLES_URL = "fusionTablesUrl";
private static final String TEXT_PLAIN_TYPE = "text/plain";
private static final int RESULT_DIALOG = 1;
private boolean hasMapsResult;
private boolean hasFusionTablesResult;
private boolean hasDocsResult;
private boolean mapsSuccess;
private boolean fusionTablesSuccess;
private boolean docsSuccess;
private boolean shareRequest;
private String shareUrl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
hasMapsResult = intent.getBooleanExtra(HAS_MAPS_RESULT, false);
hasFusionTablesResult = intent.getBooleanExtra(HAS_FUSION_TABLES_RESULT, false);
hasDocsResult = intent.getBooleanExtra(HAS_DOCS_RESULT, false);
if (!hasMapsResult && !hasFusionTablesResult && !hasDocsResult) {
finish();
return;
}
mapsSuccess = intent.getBooleanExtra(MAPS_SUCCESS, false);
fusionTablesSuccess = intent.getBooleanExtra(FUSION_TABLES_SUCCESS, false);
docsSuccess = intent.getBooleanExtra(DOCS_SUCCESS, false);
shareRequest = intent.getBooleanExtra(SHARE_REQUEST, false);
String mapsUrl = intent.getStringExtra(MAPS_URL);
String fusionTablesUrl = intent.getStringExtra(FUSION_TABLES_URL);
shareUrl = mapsUrl != null ? mapsUrl : fusionTablesUrl;
}
@Override
protected void onResume() {
super.onResume();
showDialog(RESULT_DIALOG);
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case RESULT_DIALOG:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
View view = getLayoutInflater().inflate(R.layout.upload_result, null);
builder.setView(view);
LinearLayout mapsResult = (LinearLayout) view.findViewById(R.id.upload_result_maps_result);
LinearLayout fusionTablesResult = (LinearLayout) view.findViewById(
R.id.upload_result_fusion_tables_result);
LinearLayout docsResult = (LinearLayout) view.findViewById(R.id.upload_result_docs_result);
ImageView mapsResultIcon = (ImageView) view.findViewById(
R.id.upload_result_maps_result_icon);
ImageView fusionTablesResultIcon = (ImageView) view.findViewById(
R.id.upload_result_fusion_tables_result_icon);
ImageView docsResultIcon = (ImageView) view.findViewById(
R.id.upload_result_docs_result_icon);
TextView successFooter = (TextView) view.findViewById(R.id.upload_result_success_footer);
TextView errorFooter = (TextView) view.findViewById(R.id.upload_result_error_footer);
boolean hasError = false;
if (!hasMapsResult) {
mapsResult.setVisibility(View.GONE);
} else {
if (!mapsSuccess) {
mapsResultIcon.setImageResource(R.drawable.failure);
hasError = true;
}
}
if (!hasFusionTablesResult) {
fusionTablesResult.setVisibility(View.GONE);
} else {
if (!fusionTablesSuccess) {
fusionTablesResultIcon.setImageResource(R.drawable.failure);
hasError = true;
}
}
if (!hasDocsResult) {
docsResult.setVisibility(View.GONE);
} else {
if (!docsSuccess) {
docsResultIcon.setImageResource(R.drawable.failure);
hasError = true;
}
}
if (hasError) {
builder.setTitle(R.string.generic_error_title);
builder.setIcon(android.R.drawable.ic_dialog_alert);
successFooter.setVisibility(View.GONE);
} else {
builder.setTitle(R.string.generic_success_title);
builder.setIcon(android.R.drawable.ic_dialog_info);
errorFooter.setVisibility(View.GONE);
}
builder.setCancelable(true);
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
finish();
}
});
builder.setPositiveButton(
getString(R.string.generic_ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (shareRequest && shareUrl != null) {
startShareUrlActivity(shareUrl);
}
finish();
}
});
// Add a Share URL button if not a shareRequest and shareUrl
// exists
if (!shareRequest && shareUrl != null) {
builder.setNegativeButton(getString(R.string.send_google_result_share_url),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startShareUrlActivity(shareUrl);
finish();
}
});
}
return builder.create();
default:
return null;
}
}
/**
* Starts an activity to share the url.
*
* @param url the url
*/
private void startShareUrlActivity(String url) {
SharedPreferences prefs = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean shareUrlOnly = prefs.getBoolean(getString(R.string.share_url_only_key), false);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(TEXT_PLAIN_TYPE);
intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_track_subject));
intent.putExtra(Intent.EXTRA_TEXT,
shareUrlOnly ? url : getString(R.string.share_track_url_body_format, url));
startActivity(Intent.createChooser(intent, getString(R.string.share_track_picker_title)));
}
}
@@ -1,130 +0,0 @@
/*
* Copyright 2011 Google 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 com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.apps.mytracks.MyTracks;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
/**
* Tests {@link ResultDialogFactory}.
*
* @author Matthew Simmons
*/
public class ResultDialogFactoryTest extends ActivityInstrumentationTestCase2<MyTracks> {
public ResultDialogFactoryTest() {
super(MyTracks.class);
}
private List<SendResult> makeResults(SendResult... results) {
List<SendResult> resultsList = new ArrayList<SendResult>();
for (SendResult result : results) {
resultsList.add(result);
}
return resultsList;
}
private DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {}
};
private MyTracks myTracks;
protected void setUp() throws Exception {
super.setUp();
myTracks = getActivity();
};
public void testSuccess_noShare() {
List<SendResult> results = makeResults(new SendResult(SendType.MAPS, true),
new SendResult(SendType.DOCS, true));
AlertDialog dialog = ResultDialogFactory.makeDialog(
myTracks, results, clickListener, null, null);
dialog.show();
ListView listView = (ListView) dialog.findViewById(R.id.send_to_google_result_list);
ListAdapter listAdapter = listView.getAdapter();
assertEquals(2, listAdapter.getCount());
assertEquals(SendType.MAPS, ((SendResult) listAdapter.getItem(0)).getType());
assertEquals(SendType.DOCS, ((SendResult) listAdapter.getItem(1)).getType());
// Checking the return code of Dialog#getButton doesn't appear to be
// sufficient, as a Button will be returned even if it doesn't appear in
// the rendered dialog.
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_POSITIVE).getVisibility());
assertEquals(View.GONE, dialog.getButton(AlertDialog.BUTTON_NEUTRAL).getVisibility());
assertEquals(View.VISIBLE,
dialog.findViewById(R.id.send_to_google_result_comment).getVisibility());
assertEquals(View.GONE,
dialog.findViewById(R.id.send_to_google_result_error).getVisibility());
// TODO: Test correct listener invocation. Neither TouchUtils#clickView
// nor Button#performClick appear to cause listener invocation. This
// might be Android bug
// http://code.google.com/p/android/issues/detail?id=6564
}
public void testSuccess_share() {
List<SendResult> results = makeResults(
new SendResult(SendType.MAPS, true), new SendResult(SendType.DOCS, true));
AlertDialog dialog = ResultDialogFactory.makeDialog(
myTracks, results, clickListener, clickListener, null);
dialog.show();
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_POSITIVE).getVisibility());
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_NEGATIVE).getVisibility());
}
public void testFailure_noShare() {
List<SendResult> results = makeResults(new SendResult(SendType.MAPS, true),
new SendResult(SendType.DOCS, false));
AlertDialog dialog = ResultDialogFactory.makeDialog(
myTracks, results, clickListener, null, null);
dialog.show();
assertEquals(View.GONE,
dialog.findViewById(R.id.send_to_google_result_comment).getVisibility());
assertEquals(View.VISIBLE,
dialog.findViewById(R.id.send_to_google_result_error).getVisibility());
}
public void testFailure_share() {
List<SendResult> results = makeResults(new SendResult(SendType.MAPS, true),
new SendResult(SendType.DOCS, false));
AlertDialog dialog = ResultDialogFactory.makeDialog(
myTracks, results, clickListener, clickListener, null);
dialog.show();
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_POSITIVE).getVisibility());
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_NEGATIVE).getVisibility());
}
}
@@ -1,117 +0,0 @@
/*
* Copyright 2011 Google 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 com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.test.AndroidTestCase;
import android.view.LayoutInflater;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* Tests {@link ResultListAdapter}.
*
* @author Matthew Simmons
*/
public class ResultListAdapterTest extends AndroidTestCase {
private static class TestResultListAdapter extends ResultListAdapter {
public View contentView;
public int drawableId;
public int nameId;
public int urlId;
public TestResultListAdapter(Context context, List<SendResult> results) {
super(context, 0, results);
}
@Override
protected void setImage(View content, int drawableId) {
saveContentView(content);
this.drawableId = drawableId;
}
@Override
protected void setName(View content, int nameId) {
saveContentView(content);
this.nameId = nameId;
}
@Override
protected void setUrl(View content, int urlId) {
saveContentView(content);
this.urlId = urlId;
}
@SuppressWarnings("hiding")
private void saveContentView(View contentView) {
if (this.contentView == null) {
this.contentView = contentView;
} else {
AndroidTestCase.assertEquals(this.contentView, contentView);
}
}
}
private final SendType sendType = SendType.MAPS;
private View inflateContentView(int viewId) {
LayoutInflater layoutInflater
= (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return layoutInflater.inflate(viewId, null);
}
private List<SendResult> makeResult(SendType type, boolean success) {
List<SendResult> results = new ArrayList<SendResult>();
results.add(new SendResult(type, success));
return results;
}
public void testSuccess_createsNewView() {
TestResultListAdapter adapter = new TestResultListAdapter(getContext(),
makeResult(sendType, true));
adapter.getView(0, null, null);
assertEquals(R.drawable.success, adapter.drawableId);
assertEquals(sendType.getServiceName(), adapter.nameId);
assertEquals(sendType.getServiceUrl(), adapter.urlId);
}
public void testSuccess_reusesView() {
View contentView = inflateContentView(R.layout.send_to_google_result_list_item);
TestResultListAdapter adapter = new TestResultListAdapter(getContext(),
makeResult(sendType, true));
adapter.getView(0, contentView, null);
assertEquals(contentView, adapter.contentView);
assertEquals(R.drawable.success, adapter.drawableId);
assertEquals(sendType.getServiceName(), adapter.nameId);
assertEquals(sendType.getServiceUrl(), adapter.urlId);
}
public void testFailure() {
TestResultListAdapter adapter = new TestResultListAdapter(getContext(),
makeResult(sendType, false));
adapter.getView(0, null, null);
assertEquals(R.drawable.failure, adapter.drawableId);
assertEquals(sendType.getServiceName(), adapter.nameId);
assertEquals(sendType.getServiceUrl(), adapter.urlId);
}
}