Add option to share a track via Google Drive.

This commit is contained in:
Jimmy Shih
2013-01-29 16:40:01 -08:00
parent f9bd84dba0
commit 3f173d4434
14 changed files with 345 additions and 41 deletions
@@ -21,6 +21,7 @@ import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.fragments.AddPeopleDialogFragment;
import com.google.android.apps.mytracks.fragments.ChartFragment;
import com.google.android.apps.mytracks.fragments.ChooseActivityDialogFragment;
import com.google.android.apps.mytracks.fragments.ChooseUploadServiceDialogFragment;
@@ -76,7 +77,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
private static final String TAG = TrackDetailActivity.class.getSimpleName();
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
// The following are set in onCreate
private SharedPreferences sharedPreferences;
private TrackRecordingServiceConnection trackRecordingServiceConnection;
@@ -96,6 +97,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
private MenuItem insertMarkerMenuItem;
private MenuItem playMenuItem;
private MenuItem shareMenuItem;
private MenuItem shareDriveMenuItem;
private MenuItem sendGoogleMenuItem;
private MenuItem saveMenuItem;
private MenuItem voiceFrequencyMenuItem;
@@ -294,6 +296,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
insertMarkerMenuItem = menu.findItem(R.id.track_detail_insert_marker);
playMenuItem = menu.findItem(R.id.track_detail_play);
shareMenuItem = menu.findItem(R.id.track_detail_share);
shareDriveMenuItem = menu.findItem(R.id.track_detail_share_drive);
sendGoogleMenuItem = menu.findItem(R.id.track_detail_send_google);
saveMenuItem = menu.findItem(R.id.track_detail_save);
voiceFrequencyMenuItem = menu.findItem(R.id.track_detail_voice_frequency);
@@ -312,9 +315,14 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
return super.onPrepareOptionsMenu(menu);
}
/**
* Invokes when the confirm dialog is done.
*
* @param id the confirm id
*/
public void onConfirmDialogDone(int id) {
switch (id) {
case R.string.show_confirm_play_earth_dialog_key:
case R.string.confirm_play_earth_key:
AnalyticsUtils.sendPageViews(this, "/action/play");
Intent intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
@@ -322,11 +330,15 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
.putExtra(SaveActivity.EXTRA_PLAY_TRACK, true);
startActivity(intent);
break;
case R.string.show_confirm_sharing_dialog_key:
case R.string.confirm_share_map_key:
AnalyticsUtils.sendPageViews(this, "/action/share");
ChooseActivityDialogFragment.newInstance(trackId, null).show(
getSupportFragmentManager(), ChooseActivityDialogFragment.CHOOSE_ACTIVITY_DIALOG_TAG);
break;
case R.string.confirm_share_drive_key:
AddPeopleDialogFragment.newInstance(trackId)
.show(getSupportFragmentManager(), AddPeopleDialogFragment.ADD_PEOPLE_DIALOG_TAG);
break;
default:
}
}
@@ -343,8 +355,8 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
return true;
case R.id.track_detail_play:
if (isEarthInstalled()) {
ConfirmDialogFragment.newInstance(R.string.show_confirm_play_earth_dialog_key,
PreferencesUtils.SHOW_CONFIRM_PLAY_DIALOG_DEFAULT,
ConfirmDialogFragment.newInstance(R.string.confirm_play_earth_key,
PreferencesUtils.CONFIRM_PLAY_EARTH_DEFAULT,
getString(R.string.track_detail_play_confirm_message))
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
} else {
@@ -353,10 +365,15 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
}
return true;
case R.id.track_detail_share:
ConfirmDialogFragment.newInstance(R.string.show_confirm_sharing_dialog_key,
PreferencesUtils.SHOW_CONFIRM_SHARING_DIALOG_DEFAULT,
StringUtils.getHtml(
this, R.string.share_track_confirm_message, R.string.maps_public_unlisted_url))
ConfirmDialogFragment.newInstance(R.string.confirm_share_map_key,
PreferencesUtils.CONFIRM_SHARE_MAP_DEFAULT, StringUtils.getHtml(
this, R.string.share_track_map_confirm_message, R.string.maps_public_unlisted_url))
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
return true;
case R.id.track_detail_share_drive:
ConfirmDialogFragment.newInstance(R.string.confirm_share_drive_key,
PreferencesUtils.CONFIRM_SHARE_DRIVE_DEFAULT,
getString(R.string.share_track_drive_confirm_message))
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
return true;
case R.id.track_detail_markers:
@@ -502,6 +519,9 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
if (shareMenuItem != null) {
shareMenuItem.setVisible(!isRecording);
}
if (shareDriveMenuItem != null) {
shareDriveMenuItem.setVisible(!isRecording);
}
if (sendGoogleMenuItem != null) {
sendGoogleMenuItem.setVisible(!isRecording);
}
@@ -0,0 +1,125 @@
/*
* Copyright 2013 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.fragments;
import com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.util.IntentUtils;
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.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.widget.FilterQueryProvider;
import android.widget.MultiAutoCompleteTextView;
/**
* A DialogFragment to add people to share a track with.
*
* @author Jimmy Shih
*/
public class AddPeopleDialogFragment extends DialogFragment {
public static final String ADD_PEOPLE_DIALOG_TAG = "addPeopleDialog";
private static final String KEY_TRACK_ID = "trackId";
public static AddPeopleDialogFragment newInstance(long trackId) {
Bundle bundle = new Bundle();
bundle.putLong(KEY_TRACK_ID, trackId);
AddPeopleDialogFragment addPeopleDialogFragment = new AddPeopleDialogFragment();
addPeopleDialogFragment.setArguments(bundle);
return addPeopleDialogFragment;
}
private MultiAutoCompleteTextView multiAutoCompleteTextView;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
FragmentActivity activity = getActivity();
View view = activity.getLayoutInflater().inflate(R.layout.add_people, null);
multiAutoCompleteTextView = (MultiAutoCompleteTextView) view.findViewById(R.id.add_people);
multiAutoCompleteTextView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
SimpleCursorAdapter adapter = new SimpleCursorAdapter(getActivity(), R.layout.add_people_item,
getCursor(getActivity(), null), new String[] {
ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Email.DATA },
new int[] { android.R.id.text1, android.R.id.text2 }, 0);
adapter.setCursorToStringConverter(new SimpleCursorAdapter.CursorToStringConverter() {
@Override
public CharSequence convertToString(Cursor cursor) {
int index = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA);
return cursor.getString(index).trim();
}
});
adapter.setFilterQueryProvider(new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence constraint) {
return getCursor(getActivity(), constraint);
}
});
multiAutoCompleteTextView.setAdapter(adapter);
return new AlertDialog.Builder(activity).setNegativeButton(R.string.generic_cancel, null)
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String acl = multiAutoCompleteTextView.getText().toString();
if (acl != null && !acl.equals("")) {
long trackId = getArguments().getLong(KEY_TRACK_ID);
SendRequest sendRequest = new SendRequest(trackId);
sendRequest.setSendDrive(true);
sendRequest.setAcl(acl);
Intent intent = IntentUtils.newIntent(getActivity(), AccountChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
}
}
}).setTitle(R.string.share_track_add_people).setView(view).create();
}
/**
* Gets the cursor
*
* @param activity the activity
* @param constraint the constraint
*/
private Cursor getCursor(Activity activity, CharSequence constraint) {
String order = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1'";
if (constraint != null) {
selection += " AND (" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE '%" + constraint
+ "%' OR " + ContactsContract.CommonDataKinds.Email.DATA + " LIKE '%" + constraint
+ "%' )";
}
String[] projection = new String[] { ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Email.DATA };
Uri uri = ContactsContract.CommonDataKinds.Email.CONTENT_URI;
return activity.getContentResolver().query(uri, projection, selection, null, order);
}
}
@@ -38,7 +38,8 @@ public class SendDriveActivity extends AbstractSendActivity {
@Override
protected AbstractSendAsyncTask createAsyncTask() {
return new SendDriveAsyncTask(this, sendRequest.getTrackId(), sendRequest.getAccount());
return new SendDriveAsyncTask(
this, sendRequest.getTrackId(), sendRequest.getAccount(), sendRequest.getAcl());
}
@Override
@@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.io.sync.SyncUtils;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.Permission;
import android.accounts.Account;
import android.content.Context;
@@ -42,12 +43,18 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
private final long trackId;
private final Account account;
private final Context context;
private final String[] acl;
private final MyTracksProviderUtils myTracksProviderUtils;
public SendDriveAsyncTask(SendDriveActivity activity, long trackId, Account account) {
public SendDriveAsyncTask(SendDriveActivity activity, long trackId, Account account, String acl) {
super(activity);
this.trackId = trackId;
this.account = account;
if (acl != null) {
this.acl = acl.split(",");
} else {
this.acl = null;
}
context = activity.getApplicationContext();
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
@@ -78,13 +85,22 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
if (driveId != null && !driveId.equals("")) {
File driveFile = drive.files().get(driveId).execute();
if (SyncUtils.isDriveFileValid(driveFile, folderId)) {
return SyncUtils.updateDriveFile(context, myTracksProviderUtils, drive, driveFile, track);
if (SyncUtils.updateDriveFile(context, myTracksProviderUtils, drive, driveFile, track)) {
addPermission(drive, driveId);
return true;
}
}
track.setDriveId("");
track.setModifiedTime(-1L);
myTracksProviderUtils.updateTrack(track);
}
return SyncUtils.addDriveFile(context, myTracksProviderUtils, drive, folderId, track);
String id = SyncUtils.addDriveFile(context, myTracksProviderUtils, drive, folderId, track);
if (id == null) {
return false;
}
addPermission(drive, id);
return true;
} catch (IOException e) {
Log.e(TAG, "IOException", e);
return false;
@@ -93,4 +109,25 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
@Override
protected void invalidateToken() {}
/**
* Adds permision.
*
* @param drive the drive
* @param driveId the drive id
*/
private void addPermission(Drive drive, String driveId) throws IOException {
if (acl != null) {
for (String email : acl) {
email = email.trim();
if (!email.equals("")) {
Permission permission = new Permission();
permission.setValue(email);
permission.setType("user");
permission.setRole("reader");
drive.permissions().insert(driveId, permission).execute();
}
}
}
}
}
@@ -33,6 +33,7 @@ public class SendRequest implements Parcelable {
private long trackId = -1L;
private String sharingAppPackageName = null;
private String sharingAppClassName = null;
private String acl = null;
private boolean sendDrive = false;
private boolean sendMaps = false;
private boolean sendFusionTables = false;
@@ -93,6 +94,22 @@ public class SendRequest implements Parcelable {
this.sharingAppClassName = sharingAppClassName;
}
/**
* Gets the email address of the user to share the track with.
*/
public String getAcl() {
return acl;
}
/**
* Sets the email address of the user to share the track with.
*
* @param acl the email address
*/
public void setAcl(String acl) {
this.acl = acl;
}
/**
* True if the user has selected the send to Google Drive option.
*/
@@ -279,6 +296,7 @@ public class SendRequest implements Parcelable {
trackId = in.readLong();
sharingAppPackageName = in.readString();
sharingAppClassName = in.readString();
acl = in.readString();
sendDrive = in.readByte() == 1;
sendMaps = in.readByte() == 1;
sendFusionTables = in.readByte() == 1;
@@ -302,6 +320,7 @@ public class SendRequest implements Parcelable {
out.writeLong(trackId);
out.writeString(sharingAppPackageName);
out.writeString(sharingAppClassName);
out.writeString(acl);
out.writeByte((byte) (sendDrive ? 1 : 0));
out.writeByte((byte) (sendMaps ? 1 : 0));
out.writeByte((byte) (sendFusionTables ? 1 : 0));
@@ -295,13 +295,14 @@ public class SyncUtils {
* @param drive the drive
* @param folderId the folder id
* @param track the track
* @return the added drive file id or null.
*/
public static boolean addDriveFile(Context context, MyTracksProviderUtils myTracksProviderUtils,
public static String addDriveFile(Context context, MyTracksProviderUtils myTracksProviderUtils,
Drive drive, String folderId, Track track) throws IOException {
java.io.File file = getFile(context, myTracksProviderUtils, track);
if (file == null) {
Log.e(TAG, "Unable to add Drive file. File is null for track " + track.getName());
return false;
return null;
}
try {
@@ -323,12 +324,13 @@ public class SyncUtils {
File uploadedFile = drive.files().insert(newMetaData, fileContent).execute();
if (uploadedFile == null) {
Log.e(TAG, "Unable to add Drive file. Uploaded file is null for track " + track.getName());
return false;
return null;
}
track.setDriveId(uploadedFile.getId());
String id = uploadedFile.getId();
track.setDriveId(id);
track.setModifiedTime(uploadedFile.getModifiedDate().getValue());
myTracksProviderUtils.updateTrack(track);
return true;
return id;
} finally {
file.delete();
}
@@ -49,6 +49,11 @@ public class PreferencesUtils {
public static final boolean CHART_SHOW_HEART_RATE_DEFAULT = true;
public static final boolean CHART_SHOW_POWER_DEFAULT = true;
public static final boolean CHART_SHOW_SPEED_DEFAULT = true;
public static final boolean CONFIRM_PLAY_EARTH_DEFAULT = true;
public static final boolean CONFIRM_SHARE_DRIVE_DEFAULT = true;
public static final boolean CONFIRM_SHARE_MAP_DEFAULT = true;
public static final String DEFAULT_ACTIVITY_DEFAULT = "";
public static final boolean DEFAULT_MAP_PUBLIC_DEFAULT = false;
public static final String DRIVE_DELETED_LIST_DEFAULT = "";
@@ -85,8 +90,6 @@ public class PreferencesUtils {
public static final boolean SEND_TO_MAPS_DEFAULT = false;
public static final String SENSOR_TYPE_DEFAULT = "NONE";
public static final boolean SHOW_CONFIRM_PLAY_DIALOG_DEFAULT = true;
public static final boolean SHOW_CONFIRM_SHARING_DIALOG_DEFAULT = true;
public static final int SPLIT_FREQUENCY_DEFAULT = 0;
public static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
public static final boolean STATS_SHOW_ELEVATION_DEFAULT = false;