/*
* 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.endtoendtest;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
import com.google.android.apps.mytracks.io.gdata.maps.MapFeatureEntry;
import com.google.android.apps.mytracks.io.gdata.maps.MapsClient;
import com.google.android.apps.mytracks.io.gdata.maps.MapsConstants;
import com.google.android.apps.mytracks.io.gdata.maps.MapsGDataConverter;
import com.google.android.apps.mytracks.io.gdata.maps.MapsMapMetadata;
import com.google.android.apps.mytracks.io.gdata.maps.XmlMapsGDataParserFactory;
import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
import com.google.android.apps.mytracks.io.spreadsheets.SendSpreadsheetsAsyncTask;
import com.google.android.apps.mytracks.io.sync.SyncUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.common.gdata.AndroidXmlParserFactory;
import com.google.android.maps.mytracks.R;
import com.google.api.client.auth.oauth2.BearerToken;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import com.google.api.services.fusiontables.Fusiontables;
import com.google.api.services.fusiontables.model.Table;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.spreadsheet.ListEntry;
import com.google.gdata.data.spreadsheet.ListFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetFeed;
import com.google.wireless.gdata.parser.GDataParser;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.util.Log;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
/**
* Utilities for accessing Google Drive, Google Maps, Google Fusion Tables, and
* Google Spreadsheets.
*
* @author Youtao Liu
*/
public class GoogleUtils {
public static final String ACCOUNT_1 = "mytrackstest@gmail.com";
public static final String ACCOUNT_2 = "mytrackstest2@gmail.com";
private static final String TAG = GoogleUtils.class.getSimpleName();
private static final String MY_TRACKS_PREFIX = "My Tracks";
private static final String SPREADSHEETS_NAME = MY_TRACKS_PREFIX + "-"
+ EndToEndTestUtils.activityType;
private static final String SPREADSHEETS_WORKSHEET_NAME = "Log";
private static final String SPREADSHEETS_TRANCK_NAME_COLUMN = "Name";
private static final String DRIVE_TEST_FILES_QUERY = "'root' in parents and title contains '"
+ EndToEndTestUtils.TRACK_NAME_PREFIX + "' and trashed = false";
/**
* Deletes Google Drive test files.
*
* @param context the context
* @param accountName the account name
*/
public static void deleteDriveTestFiles(Context context, String accountName) {
try {
GoogleAccountCredential googleAccountCredential = SendToGoogleUtils
.getGoogleAccountCredential(context, accountName, SendToGoogleUtils.DRIVE_SCOPE);
if (googleAccountCredential == null) {
return;
}
Drive drive = SyncUtils.getDriveService(googleAccountCredential);
com.google.api.services.drive.Drive.Files.List list = drive.files()
.list().setQ(DRIVE_TEST_FILES_QUERY);
List<File> files = list.execute().getItems();
Iterator<File> iterator = files.iterator();
while (iterator.hasNext()) {
File file = (File) iterator.next();
drive.files().delete(file.getId()).execute();
}
} catch (Exception e) {
Log.e(TAG, "Unable to delete Google Drive test files.", e);
}
}
/**
* Deletes Google Maps of the first Google account.
*
* @param context the context
* @param accountName the account name
* @param mapTitle the map title
* @return true if deletion is success.
*/
public static boolean deleteMaps(Context context, String accountName, String mapTitle) {
Account account = getGoogleAccount(context, accountName);
if (account == null) {
return false;
}
MapsClient mapsClient = new MapsClient(GDataClientFactory.getGDataClient(context),
new XmlMapsGDataParserFactory(new AndroidXmlParserFactory()));
ArrayList<MapsMapMetadata> mapMetadata = getMaps(context, account, mapsClient);
for (MapsMapMetadata data : mapMetadata) {
if (data.getDescription().indexOf(MY_TRACKS_PREFIX) > -1
&& data.getTitle().equals(mapTitle)) {
try {
mapsClient.deleteEntry(data.getGDataEditUri(), AccountManager.get(context)
.blockingGetAuthToken(account, MapsConstants.SERVICE_NAME, false));
return true;
} catch (Exception e) {
Log.e(TAG, "Unable to delete maps.", e);
return false;
}
}
}
return false;
}
/**
* Deletes all Google Maps of the first Google account
*
* @param context the context
* @param accountName the account name
*/
public static void deleteAllMaps(Context context, String accountName) {
Account account = getGoogleAccount(context, accountName);
if (account == null) {
Log.e(TAG, "Unable to get account.");
return;
}
MapsClient mapsClient = new MapsClient(GDataClientFactory.getGDataClient(context),
new XmlMapsGDataParserFactory(new AndroidXmlParserFactory()));
ArrayList<MapsMapMetadata> mapMetadata = getMaps(context, account, mapsClient);
for (MapsMapMetadata oneData : mapMetadata) {
try {
mapsClient.deleteEntry(oneData.getGDataEditUri(), AccountManager.get(context)
.blockingGetAuthToken(account, MapsConstants.SERVICE_NAME, false));
} catch (Exception e) {
Log.e(TAG, "Unable to delete maps.", e);
}
}
}
/**
* Deletes Google Fusion Tables.
*
* @param context the context
* @param accountName the account name
* @param tableName the table name
* @return true if deletion is success.
*/
public static boolean deleteFusionTables(Context context, String accountName, String tableName) {
try {
GoogleAccountCredential googleAccountCredential = SendToGoogleUtils
.getGoogleAccountCredential(context, accountName, SendToGoogleUtils.FUSION_TABLES_SCOPE);
if (googleAccountCredential == null) {
return false;
}
Fusiontables fusiontables = new Fusiontables.Builder(
AndroidHttp.newCompatibleTransport(), new GsonFactory(), googleAccountCredential).build();
List<Table> tables = fusiontables.table().list().execute().getItems();
Iterator<Table> iterator = tables.iterator();
while (iterator.hasNext()) {
Table table = (Table) iterator.next();
String name = table.getName();
if (name != null && name.equals(tableName)) {
fusiontables.table().delete(table.getTableId()).execute();
return true;
}
}
} catch (Exception e) {
Log.e(TAG, "Unable to search fusion tables.", e);
}
return false;
}
/**
* Searches Google Spreadsheets.
*
* @param context the context
* @param accountName the account name
* @return the list of spreadsheets matching the title. Null if unable to
* search.
*/
public static List<File> searchSpreadsheets(Context context, String accountName) {
try {
GoogleAccountCredential googleAccountCredential = SendToGoogleUtils
.getGoogleAccountCredential(context, accountName, SendToGoogleUtils.DRIVE_SCOPE);
if (googleAccountCredential == null) {
return null;
}
Drive drive = SyncUtils.getDriveService(googleAccountCredential);
com.google.api.services.drive.Drive.Files.List list = drive.files().list().setQ(String.format(
Locale.US, SendSpreadsheetsAsyncTask.GET_SPREADSHEET_QUERY, SPREADSHEETS_NAME));
return list.execute().getItems();
} catch (Exception e) {
Log.e(TAG, "Unable to search spreadsheets.", e);
}
return null;
}
/**
* Deletes Google Spreadsheets.
*
* @param context the context
* @param accountName the account name
* @return true if deletion is success.
*/
public static boolean deleteSpreadsheets(Context context, String accountName) {
try {
GoogleAccountCredential googleAccountCredential = SendToGoogleUtils
.getGoogleAccountCredential(context, accountName, SendToGoogleUtils.DRIVE_SCOPE);
if (googleAccountCredential == null) {
return false;
}
Drive drive = SyncUtils.getDriveService(googleAccountCredential);
com.google.api.services.drive.Drive.Files.List list = drive.files().list().setQ(String.format(
Locale.US, SendSpreadsheetsAsyncTask.GET_SPREADSHEET_QUERY, SPREADSHEETS_NAME));
List<File> files = list.execute().getItems();
Iterator<File> iterator = files.iterator();
while (iterator.hasNext()) {
File file = (File) iterator.next();
drive.files().delete(file.getId()).execute();
}
return true;
} catch (Exception e) {
Log.e(TAG, "Unable to delete spreadsheets.", e);
}
return false;
}
/**
* Deletes Google Spreadsheets row.
*
* @param context the context
* @param accountName the account name
* @param trackName the track name
* @return true if deletion is success.
*/
public static boolean deleteSpreadsheetsRow(
Context context, String accountName, String trackName) {
try {
// Get spreadsheet Id
List<File> files = searchSpreadsheets(context, accountName);
if (files == null || files.size() == 0) {
return false;
}
String spreadsheetId = files.get(0).getId();
// Get spreadsheet service
SpreadsheetService spreadsheetService = new SpreadsheetService(
"MyTracks-" + SystemUtils.getMyTracksVersion(context));
Credential credential = new Credential(BearerToken.authorizationHeaderAccessMethod());
credential.setAccessToken(
SendToGoogleUtils.getToken(context, accountName, SendToGoogleUtils.SPREADSHEETS_SCOPE));
spreadsheetService.setOAuth2Credentials(credential);
// Get work sheet
WorksheetFeed worksheetFeed = spreadsheetService.getFeed(new URL(
String.format(Locale.US, SendSpreadsheetsAsyncTask.GET_WORKSHEETS_URI, spreadsheetId)),
WorksheetFeed.class);
Iterator<WorksheetEntry> worksheetEntryIterator = worksheetFeed.getEntries().iterator();
while (worksheetEntryIterator.hasNext()) {
WorksheetEntry worksheetEntry = (WorksheetEntry) worksheetEntryIterator.next();
String worksheetTitle = worksheetEntry.getTitle().getPlainText();
if (worksheetTitle.equals(SPREADSHEETS_WORKSHEET_NAME)) {
URL url = worksheetEntry.getListFeedUrl();
Iterator<ListEntry> listEntryIterator = spreadsheetService.getFeed(url, ListFeed.class)
.getEntries().iterator();
while (listEntryIterator.hasNext()) {
ListEntry listEntry = (ListEntry) listEntryIterator.next();
String name = listEntry.getCustomElements().getValue(SPREADSHEETS_TRANCK_NAME_COLUMN);
if (name.equals(trackName)) {
listEntry.delete();
return true;
}
}
}
}
} catch (Exception e) {
Log.e(TAG, "Unable to delete spreadsheets row.", e);
}
return false;
}
/**
* Returns true if an account is available.
*/
public static boolean isAccountAvailable() {
// Check the no account dialog
if (EndToEndTestUtils.SOLO.waitForText(
EndToEndTestUtils.trackListActivity.getString(R.string.send_google_no_account_title), 1,
EndToEndTestUtils.SHORT_WAIT_TIME)) {
EndToEndTestUtils.getButtonOnScreen(
EndToEndTestUtils.trackListActivity.getString(R.string.generic_ok), false, true);
return false;
}
// Check the choose account dialog
if (EndToEndTestUtils.SOLO.waitForText(
EndToEndTestUtils.trackListActivity.getString(R.string.send_google_choose_account_title), 1,
EndToEndTestUtils.SHORT_WAIT_TIME)) {
EndToEndTestUtils.SOLO.clickOnText(ACCOUNT_1);
EndToEndTestUtils.getButtonOnScreen(
EndToEndTestUtils.trackListActivity.getString(R.string.generic_ok), false, true);
}
// Check the no account permission dialog
if (EndToEndTestUtils.SOLO.waitForText(
EndToEndTestUtils.trackListActivity.getString(R.string.send_google_no_account_permission), 1,
EndToEndTestUtils.SHORT_WAIT_TIME)) {
return false;
}
return true;
}
/**
* Gets the google account.
*
* @param context the context
* @param accountName the account name
*/
private static Account getGoogleAccount(Context context, String accountName) {
Account[] accounts = AccountManager.get(context).getAccountsByType(Constants.ACCOUNT_TYPE);
for (Account account : accounts) {
if (account.name.equals(accountName)) {
return account;
}
}
return null;
}
/**
* Gets Google Maps.
*
* @param context the context
* @param account the account
* @param mapsClient the map client
* @return a list of maps.
*/
private static ArrayList<MapsMapMetadata> getMaps(
Context context, Account account, MapsClient mapsClient) {
String authToken = null;
ArrayList<String> mapIds = new ArrayList<String>();
ArrayList<MapsMapMetadata> mapMetadata = new ArrayList<MapsMapMetadata>();
try {
authToken = AccountManager.get(context)
.blockingGetAuthToken(account, MapsConstants.SERVICE_NAME, false);
} catch (Exception e) {
Log.e(TAG, "Unable to get auth token.", e);
return mapMetadata;
}
GDataParser gDataParser = null;
try {
gDataParser = mapsClient.getParserForFeed(
MapFeatureEntry.class, MapsClient.getMapsFeed(), authToken);
gDataParser.init();
while (gDataParser.hasMoreData()) {
MapFeatureEntry entry = (MapFeatureEntry) gDataParser.readNextEntry(null);
mapIds.add(MapsGDataConverter.getMapidForEntry(entry));
mapMetadata.add(MapsGDataConverter.getMapMetadataForEntry(entry));
}
} catch (Exception e) {
Log.e(TAG, "Unable to get maps.", e);
} finally {
if (gDataParser != null) {
gDataParser.close();
}
}
return mapMetadata;
}
}