package org.jetbrains.android.database; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.IDevice; import com.intellij.CommonBundle; import com.intellij.database.psi.DbDataSourceElement; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.diagnostic.Logger; 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 org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import static com.intellij.database.view.DatabaseView.getSelectedElements; /** * @author Eugene.Kudelevsky */ public class AndroidUploadDatabaseAction extends AnAction { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.database.AndroidUploadDatabaseAction"); @Override public void update(AnActionEvent e) { final Project project = e.getProject(); e.getPresentation().setVisible(project != null && !getSelectedAndroidDataSources(e).isEmpty()); } @Override public void actionPerformed(AnActionEvent e) { final Project project = e.getProject(); assert project != null; final List<AndroidDataSource> dataSources = getSelectedAndroidDataSources(e); final AndroidDebugBridge debugBridge = AndroidSdkUtils.getDebugBridge(project); if (debugBridge == null) { Messages.showErrorDialog(project, AndroidBundle.message("cannot.connect.to.adb.error"), CommonBundle.getErrorTitle()); return; } ProgressManager.getInstance().run(new Task.Backgroundable(project, AndroidBundle.message("android.db.uploading.progress.title"), true) { @Override public void run(@NotNull ProgressIndicator indicator) { for (final AndroidDataSource dataSource : dataSources) { indicator.setText("Uploading " + dataSource.getName()); synchronized (AndroidDbUtil.DB_SYNC_LOCK) { uploadDatabase(project, dataSource, indicator, debugBridge); } indicator.checkCanceled(); } } }); } @NotNull private static List<AndroidDataSource> getSelectedAndroidDataSources(AnActionEvent e) { final Set<DbDataSourceElement> dataSourceElements = getSelectedElements(e.getDataContext(), DbDataSourceElement.class); if (dataSourceElements.isEmpty()) { return Collections.emptyList(); } final List<AndroidDataSource> androidDataSources = new ArrayList<AndroidDataSource>(); for (DbDataSourceElement element : dataSourceElements) { final Object delegate = element.getDelegate(); if (delegate instanceof AndroidDataSource) { androidDataSources.add((AndroidDataSource)delegate); } } return androidDataSources; } private static void uploadDatabase(@NotNull Project project, @NotNull AndroidDataSource dataSource, @NotNull ProgressIndicator indicator, @NotNull AndroidDebugBridge debugBridge) { final String localDbFilePath = dataSource.buildLocalDbFileOsPath(); final AndroidDbErrorReporterImpl errorReporter = new AndroidDbErrorReporterImpl(project, dataSource, true); final AndroidDbConnectionInfo dbConnectionInfo = AndroidDbUtil.checkDataSource(dataSource, debugBridge, errorReporter); if (dbConnectionInfo == null) { return; } final IDevice device = dbConnectionInfo.getDevice(); final String packageName = dbConnectionInfo.getPackageName(); final String dbName = dbConnectionInfo.getDbName(); final String localFileMd5Hash = getLocalFileMd5Hash(new File(localDbFilePath)); final String deviceId = AndroidDbUtil.getDeviceId(device); final boolean external = dbConnectionInfo.isExternal(); if (localFileMd5Hash == null || deviceId == null) { return; } if (AndroidDbUtil.uploadDatabase(device, packageName, dbName, external, localDbFilePath, indicator, errorReporter)) { final Long modificationTime = AndroidDbUtil.getModificationTime(device, packageName, dbName, external, errorReporter, indicator); if (modificationTime != null) { AndroidRemoteDataBaseManager.MyDatabaseInfo dbInfo = AndroidRemoteDataBaseManager. getInstance().getDatabaseInfo(deviceId, packageName, dbName, external); if (dbInfo == null) { dbInfo = new AndroidRemoteDataBaseManager.MyDatabaseInfo(); } dbInfo.modificationTime = modificationTime; AndroidRemoteDataBaseManager.getInstance().setDatabaseInfo(deviceId, packageName, dbName, dbInfo, external); } } } @Nullable private static String getLocalFileMd5Hash(@NotNull File file) { try { final byte[] buffer = new byte[1024]; final MessageDigest md5 = MessageDigest.getInstance("MD5"); final InputStream fis = new BufferedInputStream(new FileInputStream(file)); try { int read; while ((read = fis.read(buffer)) > 0) { md5.update(buffer, 0, read); } } finally { fis.close(); } final StringBuilder builder = new StringBuilder(); for (byte b : md5.digest()) { builder.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); } return builder.toString(); } catch (IOException e) { LOG.error(e); return null; } catch (NoSuchAlgorithmException e) { LOG.error(e); return null; } } }