Merge change 21445 into donut
* changes: SDK Updater, restart ADB after updating tool/addon package.
This commit is contained in:
@@ -48,6 +48,7 @@ public class SettingsPage extends Composite implements ISettingsPage {
|
||||
private Text mProxyServerText;
|
||||
private Text mProxyPortText;
|
||||
private Button mForceHttpCheck;
|
||||
private Button mAskAdbRestartCheck;
|
||||
|
||||
private ModifyListener mSetApplyDirty = new ModifyListener() {
|
||||
public void modifyText(ModifyEvent e) {
|
||||
@@ -73,18 +74,26 @@ public class SettingsPage extends Composite implements ISettingsPage {
|
||||
mProxyServerLabel = new Label(mProxySettingsGroup, SWT.NONE);
|
||||
mProxyServerLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
||||
mProxyServerLabel.setText("HTTP Proxy Server");
|
||||
String tooltip = "The DNS name or IP of the HTTP proxy server to use. " +
|
||||
"When empty, no HTTP proxy is used.";
|
||||
mProxyServerLabel.setToolTipText(tooltip);
|
||||
|
||||
mProxyServerText = new Text(mProxySettingsGroup, SWT.BORDER);
|
||||
mProxyServerText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
|
||||
mProxyServerText.addModifyListener(mSetApplyDirty);
|
||||
mProxyServerText.setToolTipText(tooltip);
|
||||
|
||||
mProxyPortLabel = new Label(mProxySettingsGroup, SWT.NONE);
|
||||
mProxyPortLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
||||
mProxyPortLabel.setText("HTTP Proxy Port");
|
||||
tooltip = "The port of the HTTP proxy server to use. " +
|
||||
"When empty, the default for HTTP or HTTPS is used.";
|
||||
mProxyPortLabel.setToolTipText(tooltip);
|
||||
|
||||
mProxyPortText = new Text(mProxySettingsGroup, SWT.BORDER);
|
||||
mProxyPortText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
|
||||
mProxyPortText.addModifyListener(mSetApplyDirty);
|
||||
mProxyPortText.setToolTipText(tooltip);
|
||||
|
||||
mMiscGroup = new Group(this, SWT.NONE);
|
||||
mMiscGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
|
||||
@@ -92,7 +101,10 @@ public class SettingsPage extends Composite implements ISettingsPage {
|
||||
mMiscGroup.setLayout(new GridLayout(2, false));
|
||||
|
||||
mForceHttpCheck = new Button(mMiscGroup, SWT.CHECK);
|
||||
mForceHttpCheck.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
|
||||
mForceHttpCheck.setText("Force https://... sources to be fetched using http://...");
|
||||
mForceHttpCheck.setToolTipText("If you are not able to connect to the official Android repository " +
|
||||
"using HTTPS, enable this setting to force accessing it via HTTP.");
|
||||
mForceHttpCheck.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
@@ -100,6 +112,18 @@ public class SettingsPage extends Composite implements ISettingsPage {
|
||||
}
|
||||
});
|
||||
|
||||
mAskAdbRestartCheck = new Button(mMiscGroup, SWT.CHECK);
|
||||
mAskAdbRestartCheck.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
|
||||
mAskAdbRestartCheck.setText("Ask before restarting ADB");
|
||||
mAskAdbRestartCheck.setToolTipText("When checked, the user will be asked for permission " +
|
||||
"to restart ADB after updating an addon-on package or a tool package.");
|
||||
mAskAdbRestartCheck.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
onForceHttpSelected(); //$hide$
|
||||
}
|
||||
});
|
||||
|
||||
mApplyButton = new Button(this, SWT.NONE);
|
||||
mApplyButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
||||
mApplyButton.setText("Save && Apply");
|
||||
@@ -139,6 +163,7 @@ public class SettingsPage extends Composite implements ISettingsPage {
|
||||
mProxyServerText.setText(in_settings.getProperty(KEY_HTTP_PROXY_HOST, "")); //$NON-NLS-1$
|
||||
mProxyPortText.setText( in_settings.getProperty(KEY_HTTP_PROXY_PORT, "")); //$NON-NLS-1$
|
||||
mForceHttpCheck.setSelection(Boolean.parseBoolean(in_settings.getProperty(KEY_FORCE_HTTP)));
|
||||
mAskAdbRestartCheck.setSelection(Boolean.parseBoolean(in_settings.getProperty(KEY_ASK_ADB_RESTART)));
|
||||
|
||||
// We loaded fresh settings so there's nothing dirty to apply
|
||||
mApplyButton.setEnabled(false);
|
||||
@@ -151,6 +176,8 @@ public class SettingsPage extends Composite implements ISettingsPage {
|
||||
out_settings.setProperty(KEY_HTTP_PROXY_PORT, mProxyPortText.getText());
|
||||
out_settings.setProperty(KEY_FORCE_HTTP,
|
||||
Boolean.toString(mForceHttpCheck.getSelection()));
|
||||
out_settings.setProperty(KEY_ASK_ADB_RESTART,
|
||||
Boolean.toString(mAskAdbRestartCheck.getSelection()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* 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.android.sdkuilib.internal.repository;
|
||||
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.android.sdklib.internal.repository.ITaskMonitor;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A lightweight wrapper to start & stop ADB.
|
||||
*/
|
||||
public class AdbWrapper {
|
||||
|
||||
/*
|
||||
* Note: we could bring ddmlib in SdkManager for that purpose, however this allows us to
|
||||
* specialize the start/stop methods to our needs (e.g. a task monitor, etc.)
|
||||
*/
|
||||
|
||||
private final String mAdbOsLocation;
|
||||
private final ITaskMonitor mMonitor;
|
||||
|
||||
/**
|
||||
* Creates a new lightweight ADB wrapper.
|
||||
*
|
||||
* @param osSdkPath The root OS path of the SDK. Cannot be null.
|
||||
* @param monitor A logger object. Cannot be null.
|
||||
*/
|
||||
public AdbWrapper(String osSdkPath, ITaskMonitor monitor) {
|
||||
mMonitor = monitor;
|
||||
|
||||
if (!osSdkPath.endsWith(File.separator)) {
|
||||
osSdkPath += File.separator;
|
||||
}
|
||||
mAdbOsLocation = osSdkPath + SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_ADB;
|
||||
}
|
||||
|
||||
private void display(String format, Object...args) {
|
||||
mMonitor.setResult(format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the adb host side server.
|
||||
* @return true if success
|
||||
*/
|
||||
public synchronized boolean startAdb() {
|
||||
if (mAdbOsLocation == null) {
|
||||
display("Error: missing path to ADB."); //$NON-NLS-1$
|
||||
return false;
|
||||
}
|
||||
|
||||
Process proc;
|
||||
int status = -1;
|
||||
|
||||
try {
|
||||
String[] command = new String[2];
|
||||
command[0] = mAdbOsLocation;
|
||||
command[1] = "start-server"; //$NON-NLS-1$
|
||||
proc = Runtime.getRuntime().exec(command);
|
||||
|
||||
ArrayList<String> errorOutput = new ArrayList<String>();
|
||||
ArrayList<String> stdOutput = new ArrayList<String>();
|
||||
status = grabProcessOutput(proc, errorOutput, stdOutput,
|
||||
false /* waitForReaders */);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
display("Unable to run 'adb': %1$s.", ioe.getMessage()); //$NON-NLS-1$
|
||||
// we'll return false;
|
||||
} catch (InterruptedException ie) {
|
||||
display("Unable to run 'adb': %1$s.", ie.getMessage()); //$NON-NLS-1$
|
||||
// we'll return false;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
display("'adb start-server' failed."); //$NON-NLS-1$
|
||||
return false;
|
||||
}
|
||||
|
||||
display("'adb start-server' succeeded."); //$NON-NLS-1$
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the adb host side server.
|
||||
* @return true if success
|
||||
*/
|
||||
public synchronized boolean stopAdb() {
|
||||
if (mAdbOsLocation == null) {
|
||||
display("Error: missing path to ADB."); //$NON-NLS-1$
|
||||
return false;
|
||||
}
|
||||
|
||||
Process proc;
|
||||
int status = -1;
|
||||
|
||||
try {
|
||||
String[] command = new String[2];
|
||||
command[0] = mAdbOsLocation;
|
||||
command[1] = "kill-server"; //$NON-NLS-1$
|
||||
proc = Runtime.getRuntime().exec(command);
|
||||
status = proc.waitFor();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
// we'll return false;
|
||||
}
|
||||
catch (InterruptedException ie) {
|
||||
// we'll return false;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
display("'adb kill-server' failed -- run manually if necessary."); //$NON-NLS-1$
|
||||
return false;
|
||||
}
|
||||
|
||||
display("'adb kill-server' succeeded."); //$NON-NLS-1$
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stderr/stdout outputs of a process and return when the process is done.
|
||||
* Both <b>must</b> be read or the process will block on windows.
|
||||
* @param process The process to get the ouput from
|
||||
* @param errorOutput The array to store the stderr output. cannot be null.
|
||||
* @param stdOutput The array to store the stdout output. cannot be null.
|
||||
* @param waitforReaders if true, this will wait for the reader threads.
|
||||
* @return the process return code.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private int grabProcessOutput(final Process process, final ArrayList<String> errorOutput,
|
||||
final ArrayList<String> stdOutput, boolean waitforReaders)
|
||||
throws InterruptedException {
|
||||
assert errorOutput != null;
|
||||
assert stdOutput != null;
|
||||
// read the lines as they come. if null is returned, it's
|
||||
// because the process finished
|
||||
Thread t1 = new Thread("") { //$NON-NLS-1$
|
||||
@Override
|
||||
public void run() {
|
||||
// create a buffer to read the stderr output
|
||||
InputStreamReader is = new InputStreamReader(process.getErrorStream());
|
||||
BufferedReader errReader = new BufferedReader(is);
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
String line = errReader.readLine();
|
||||
if (line != null) {
|
||||
display("ADB Error: %1$s", line);
|
||||
errorOutput.add(line);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// do nothing.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread t2 = new Thread("") { //$NON-NLS-1$
|
||||
@Override
|
||||
public void run() {
|
||||
InputStreamReader is = new InputStreamReader(process.getInputStream());
|
||||
BufferedReader outReader = new BufferedReader(is);
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
String line = outReader.readLine();
|
||||
if (line != null) {
|
||||
display("ADB: %1$s", line);
|
||||
stdOutput.add(line);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// do nothing.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
t1.start();
|
||||
t2.start();
|
||||
|
||||
// it looks like on windows process#waitFor() can return
|
||||
// before the thread have filled the arrays, so we wait for both threads and the
|
||||
// process itself.
|
||||
if (waitforReaders) {
|
||||
try {
|
||||
t1.join();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
try {
|
||||
t2.join();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
// get the return code from the process
|
||||
return process.waitFor();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,14 +24,34 @@ import java.util.Properties;
|
||||
*/
|
||||
public interface ISettingsPage {
|
||||
|
||||
/** Java system setting picked up by {@link URL} for http proxy port. Type: String. */
|
||||
/**
|
||||
* Java system setting picked up by {@link URL} for http proxy port.
|
||||
* Type: String.
|
||||
*/
|
||||
public static final String KEY_HTTP_PROXY_PORT = "http.proxyPort"; //$NON-NLS-1$
|
||||
/** Java system setting picked up by {@link URL} for http proxy host. Type: String. */
|
||||
/**
|
||||
* Java system setting picked up by {@link URL} for http proxy host.
|
||||
* Type: String.
|
||||
*/
|
||||
public static final String KEY_HTTP_PROXY_HOST = "http.proxyHost"; //$NON-NLS-1$
|
||||
/** Setting to force using http:// instead of https:// connections. Type: Boolean. */
|
||||
/**
|
||||
* Setting to force using http:// instead of https:// connections.
|
||||
* Type: Boolean.
|
||||
* Default: False.
|
||||
*/
|
||||
public static final String KEY_FORCE_HTTP = "sdkman.force.http"; //$NON-NLS-1$
|
||||
/** Setting to display only packages that are new or updates. Type: Boolean. */
|
||||
/**
|
||||
* Setting to display only packages that are new or updates.
|
||||
* Type: Boolean.
|
||||
* Default: True.
|
||||
*/
|
||||
public static final String KEY_SHOW_UPDATE_ONLY = "sdkman.show.update.only"; //$NON-NLS-1$
|
||||
/**
|
||||
* Setting to ask for permission before restarting ADB.
|
||||
* Type: Boolean.
|
||||
* Default: True.
|
||||
*/
|
||||
public static final String KEY_ASK_ADB_RESTART = "sdkman.ask.adb.restart"; //$NON-NLS-1$
|
||||
|
||||
/** Loads settings from the given {@link Properties} container and update the page UI. */
|
||||
public abstract void loadSettings(Properties in_settings);
|
||||
|
||||
@@ -38,13 +38,11 @@ import org.eclipse.swt.events.ControlAdapter;
|
||||
import org.eclipse.swt.events.ControlEvent;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Tree;
|
||||
|
||||
@@ -26,7 +26,11 @@ import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
* Controller class to get settings values. Settings are kept in-memory.
|
||||
* Users of this class must first load the settings before changing them and save
|
||||
* them when modified.
|
||||
* <p/>
|
||||
* Settings are enumerated by constants in {@link ISettingsPage}.
|
||||
*/
|
||||
public class SettingsController {
|
||||
|
||||
@@ -41,10 +45,30 @@ public class SettingsController {
|
||||
|
||||
//--- Access to settings ------------
|
||||
|
||||
/**
|
||||
* Returns the value of the ISettingsPage#KEY_FORCE_HTTP setting.
|
||||
* @see ISettingsPage#KEY_FORCE_HTTP
|
||||
*/
|
||||
public boolean getForceHttp() {
|
||||
return Boolean.parseBoolean(mProperties.getProperty(ISettingsPage.KEY_FORCE_HTTP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the ISettingsPage#KEY_ASK_ADB_RESTART setting.
|
||||
* @see ISettingsPage#KEY_ASK_ADB_RESTART
|
||||
*/
|
||||
public boolean getAskBeforeAdbRestart() {
|
||||
String value = mProperties.getProperty(ISettingsPage.KEY_ASK_ADB_RESTART);
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the ISettingsPage#KEY_SHOW_UPDATE_ONLY setting.
|
||||
* @see ISettingsPage#KEY_SHOW_UPDATE_ONLY
|
||||
*/
|
||||
public boolean getShowUpdateOnly() {
|
||||
String value = mProperties.getProperty(ISettingsPage.KEY_SHOW_UPDATE_ONLY);
|
||||
if (value == null) {
|
||||
@@ -53,8 +77,20 @@ public class SettingsController {
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the ISettingsPage#KEY_SHOW_UPDATE_ONLY setting.
|
||||
* @param enabled True if only compatible update items should be shown.
|
||||
* @see ISettingsPage#KEY_SHOW_UPDATE_ONLY
|
||||
*/
|
||||
public void setShowUpdateOnly(boolean enabled) {
|
||||
mProperties.setProperty(ISettingsPage.KEY_SHOW_UPDATE_ONLY, Boolean.toString(enabled));
|
||||
setSetting(ISettingsPage.KEY_SHOW_UPDATE_ONLY, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper to set a boolean setting.
|
||||
*/
|
||||
private void setSetting(String key, boolean value) {
|
||||
mProperties.setProperty(key, Boolean.toString(value));
|
||||
}
|
||||
|
||||
//--- Controller methods -------------
|
||||
@@ -89,6 +125,10 @@ public class SettingsController {
|
||||
fis = new FileInputStream(f);
|
||||
|
||||
mProperties.load(fis);
|
||||
|
||||
// Properly reformat some settings to enforce their default value when missing.
|
||||
setShowUpdateOnly(getShowUpdateOnly());
|
||||
setSetting(ISettingsPage.KEY_ASK_ADB_RESTART, getAskBeforeAdbRestart());
|
||||
}
|
||||
|
||||
} catch (AndroidLocationException e) {
|
||||
|
||||
@@ -34,6 +34,8 @@ import com.android.sdklib.internal.repository.Package.UpdateInfo;
|
||||
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
|
||||
import com.android.sdkuilib.repository.UpdaterWindow.ISdkListener;
|
||||
|
||||
import org.eclipse.jface.dialogs.MessageDialog;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -294,14 +296,15 @@ class UpdaterData {
|
||||
break;
|
||||
}
|
||||
|
||||
if (archive.install(mOsSdkRoot, forceHttp, mSdkManager, monitor)) {
|
||||
numInstalled++;
|
||||
|
||||
// Check if we successfully installed a tool or add-on package.
|
||||
if (archive.getParentPackage() instanceof AddonPackage) {
|
||||
installedAddon = true;
|
||||
} else if (archive.getParentPackage() instanceof ToolPackage) {
|
||||
installedTools = true;
|
||||
}
|
||||
|
||||
if (archive.install(mOsSdkRoot, forceHttp, mSdkManager, monitor)) {
|
||||
numInstalled++;
|
||||
}
|
||||
|
||||
} catch (Throwable t) {
|
||||
@@ -334,8 +337,10 @@ class UpdaterData {
|
||||
// Update the USB vendor ids for adb
|
||||
try {
|
||||
mSdkManager.updateAdb();
|
||||
monitor.setResult("Updated ADB to support the USB devices declared in the SDK add-ons.");
|
||||
} catch (Exception e) {
|
||||
mSdkLog.error(e, "Update ADB failed");
|
||||
monitor.setResult("failed to update adb to support the USB devices declared in the SDK add-ons.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,8 +351,11 @@ class UpdaterData {
|
||||
// before updating the tools folder, as adb.exe is (surprisingly) not
|
||||
// locked.
|
||||
|
||||
// TODO either bring in ddmlib and use its existing methods to stop adb
|
||||
// or use a shell exec to tools/adb.
|
||||
askForAdbRestart(monitor);
|
||||
}
|
||||
|
||||
if (installedTools) {
|
||||
notifyToolsNeedsToBeRestarted();
|
||||
}
|
||||
|
||||
if (numInstalled == 0) {
|
||||
@@ -364,6 +372,54 @@ class UpdaterData {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attemps to restart ADB.
|
||||
*
|
||||
* If the "ask before restart" setting is set (the default), prompt the user whether
|
||||
* now is a good time to restart ADB.
|
||||
* @param monitor
|
||||
*/
|
||||
private void askForAdbRestart(ITaskMonitor monitor) {
|
||||
final boolean[] canRestart = new boolean[] { true };
|
||||
|
||||
if (getSettingsController().getAskBeforeAdbRestart()) {
|
||||
// need to ask for permission first
|
||||
Display display = mWindowShell.getDisplay();
|
||||
|
||||
display.syncExec(new Runnable() {
|
||||
public void run() {
|
||||
canRestart[0] = MessageDialog.openQuestion(mWindowShell,
|
||||
"ADB Restart",
|
||||
"A package that depends on ADB has been updated. It is recommended " +
|
||||
"to restart ADB. Is it OK to do it now? If not, you can restart it " +
|
||||
"manually later.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (canRestart[0]) {
|
||||
AdbWrapper adb = new AdbWrapper(getOsSdkRoot(), monitor);
|
||||
adb.stopAdb();
|
||||
adb.startAdb();
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyToolsNeedsToBeRestarted() {
|
||||
Display display = mWindowShell.getDisplay();
|
||||
|
||||
display.syncExec(new Runnable() {
|
||||
public void run() {
|
||||
MessageDialog.openInformation(mWindowShell,
|
||||
"Android Tools Updated",
|
||||
"The Android SDK tool that you are currently using has been updated. " +
|
||||
"It is recommended that you now close the Android SDK window and re-open it. " +
|
||||
"If you started this window from Eclipse, please check if the Android " +
|
||||
"plug-in needs to be updated.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tries to update all the *existing* local packages.
|
||||
* This first refreshes all sources, then compares the available remote packages with
|
||||
|
||||
Reference in New Issue
Block a user