blob: 4dc513fd5b02a3b556da614b9433d09f6b36de7c [file] [log] [blame]
package org.jetbrains.android.database;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.IDevice;
import com.intellij.CommonBundle;
import com.intellij.database.SynchronizeHandler;
import com.intellij.database.psi.DbDataSourceElement;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.sdk.AndroidSdkUtils;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidSynchronizeHandler extends SynchronizeHandler {
@Override
public void synchronizationStarted(@NotNull final Project project,
@NotNull Set<DbDataSourceElement> elements) {
final List<AndroidDataSource> dataSourcesToSync = new ArrayList<AndroidDataSource>();
for (DbDataSourceElement element : elements) {
final Object delegate = element.getDelegate();
if (delegate instanceof AndroidDataSource) {
dataSourcesToSync.add((AndroidDataSource)delegate);
}
}
if (dataSourcesToSync.isEmpty()) {
return;
}
final Set<AndroidDataSource> syncedDataSources = doSynchronize(project, dataSourcesToSync);
for (Iterator<DbDataSourceElement> it = elements.iterator(); it.hasNext(); ) {
final DbDataSourceElement element = it.next();
final Object delegate = element.getDelegate();
if (delegate instanceof AndroidDataSource && !syncedDataSources.contains(delegate)) {
it.remove();
}
}
}
@NotNull
public static Set<AndroidDataSource> doSynchronize(@NotNull final Project project,
@NotNull final Collection<AndroidDataSource> dataSourcesToSync) {
final AndroidDebugBridge debugBridge = AndroidSdkUtils.getDebugBridge(project);
if (debugBridge == null) {
Messages.showErrorDialog(project, AndroidBundle.message("cannot.connect.to.adb.error"), CommonBundle.getErrorTitle());
return Collections.emptySet();
}
final Set<AndroidDataSource> syncedDataSources = Collections.synchronizedSet(new HashSet<AndroidDataSource>(dataSourcesToSync));
final MySynchronizeDataSourcesTask task = new MySynchronizeDataSourcesTask(project, debugBridge, syncedDataSources);
ProgressManager.getInstance().run(task);
return syncedDataSources;
}
private static void doSynchronizeDataSource(@NotNull Project project,
@NotNull AndroidDataSource dataSource,
@NotNull ProgressIndicator progressIndicator,
@NotNull AndroidDebugBridge debugBridge,
@NotNull AndroidDbErrorReporter errorReporter) {
final AndroidDbConnectionInfo dbConnectionInfo = AndroidDbUtil.checkDataSource(dataSource, debugBridge, errorReporter);
if (dbConnectionInfo == null) {
return;
}
final IDevice device = dbConnectionInfo.getDevice();
final String deviceId = AndroidDbUtil.getDeviceId(device);
if (deviceId == null) {
return;
}
final String packageName = dbConnectionInfo.getPackageName();
final String dbName = dbConnectionInfo.getDbName();
final boolean external = dbConnectionInfo.isExternal();
final Long modificationTime = AndroidDbUtil.getModificationTime(
device, packageName, dbName, external, errorReporter, progressIndicator);
progressIndicator.checkCanceled();
if (modificationTime == null) {
return;
}
final AndroidRemoteDataBaseManager remoteDbManager = AndroidRemoteDataBaseManager.getInstance();
AndroidRemoteDataBaseManager.MyDatabaseInfo info =
remoteDbManager.getDatabaseInfo(deviceId, packageName, dbName, external);
if (info == null) {
info = new AndroidRemoteDataBaseManager.MyDatabaseInfo();
}
progressIndicator.checkCanceled();
final File localDbFile = new File(dataSource.buildLocalDbFileOsPath());
info.referringProjects.add(FileUtil.toCanonicalPath(project.getBasePath()));
if (!localDbFile.exists() || !modificationTime.equals(info.modificationTime)) {
if (AndroidDbUtil.downloadDatabase(device, packageName, dbName, external, localDbFile, progressIndicator, errorReporter)) {
info.modificationTime = modificationTime;
remoteDbManager.setDatabaseInfo(deviceId, packageName, dbName, info, external);
}
}
}
private static class MySynchronizeDataSourcesTask extends Task.Modal {
private final Project myProject;
private final AndroidDebugBridge myDebugBridge;
private final Set<AndroidDataSource> myDataSources;
public MySynchronizeDataSourcesTask(@NotNull Project project,
@NotNull AndroidDebugBridge debugBridge,
@NotNull Set<AndroidDataSource> dataSources) {
super(project, AndroidBundle.message("android.db.downloading.progress.title"), true);
myProject = project;
myDebugBridge = debugBridge;
myDataSources = dataSources;
}
@Override
public void run(@NotNull ProgressIndicator indicator) {
for (Iterator<AndroidDataSource> it = myDataSources.iterator(); it.hasNext(); ) {
final AndroidDataSource dataSource = it.next();
indicator.setText("Downloading '" + dataSource.getName() + "'");
synchronized (AndroidDbUtil.DB_SYNC_LOCK) {
final AndroidDbErrorReporter errorReporter = new AndroidDbErrorReporterImpl(myProject, dataSource, false);
doSynchronizeDataSource(myProject, dataSource, indicator, myDebugBridge, errorReporter);
if (errorReporter.hasError()) {
it.remove();
}
}
indicator.checkCanceled();
}
}
}
}