| 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(); |
| } |
| } |
| } |
| } |