SDK Updater: update all existing local archives, license click through.
This commit is contained in:
@@ -190,6 +190,9 @@ public class AddonPackage extends Package {
|
|||||||
|
|
||||||
String name = String.format("%s-%d", getName(), getApiLevel()); // $NON-NLS-1$
|
String name = String.format("%s-%d", getName(), getApiLevel()); // $NON-NLS-1$
|
||||||
|
|
||||||
|
// FIXME this will fail if the name is not ASCII compatible. This could easily
|
||||||
|
// happen: a Chinese or Japanese name etc for example,
|
||||||
|
// to name a few.
|
||||||
name = name.toLowerCase();
|
name = name.toLowerCase();
|
||||||
name = name.replaceAll("[^a-zA-Z0-9_-]+", "_"); // $NON-NLS-1$
|
name = name.replaceAll("[^a-zA-Z0-9_-]+", "_"); // $NON-NLS-1$
|
||||||
name = name.replaceAll("_+", "_"); // $NON-NLS-1$
|
name = name.replaceAll("_+", "_"); // $NON-NLS-1$
|
||||||
@@ -199,4 +202,26 @@ public class AddonPackage extends Package {
|
|||||||
// TODO find similar existing addon in addons folder
|
// TODO find similar existing addon in addons folder
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes whether the given addon package is a suitable update for the current package.
|
||||||
|
* The base method checks the class type.
|
||||||
|
* The addon package also tests that the name is the same and the revision number is greater.
|
||||||
|
* <p/>
|
||||||
|
* An update is just that: a new package that supersedes the current one. If the new
|
||||||
|
* package has the same revision as the current one, it's not an update.
|
||||||
|
*
|
||||||
|
* @param replacementPackage The potential replacement package.
|
||||||
|
* @return True if the replacement package is a suitable update for this one.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean canBeUpdatedBy(Package replacementPackage) {
|
||||||
|
if (!super.canBeUpdatedBy(replacementPackage)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddonPackage newPkg = (AddonPackage) replacementPackage;
|
||||||
|
return newPkg.getName().equalsIgnoreCase(this.getName()) &&
|
||||||
|
newPkg.getRevision() > this.getRevision();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,4 +104,27 @@ public class DocPackage extends Package {
|
|||||||
public File getInstallFolder(String osSdkRoot) {
|
public File getInstallFolder(String osSdkRoot) {
|
||||||
return new File(osSdkRoot, SdkConstants.FD_DOCS);
|
return new File(osSdkRoot, SdkConstants.FD_DOCS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes whether the given doc package is a suitable update for the current package.
|
||||||
|
* The base method checks the class type.
|
||||||
|
* The doc package also tests the API level and revision number: the revision number must
|
||||||
|
* always be bumped. The API level can be the same or greater.
|
||||||
|
* <p/>
|
||||||
|
* An update is just that: a new package that supersedes the current one. If the new
|
||||||
|
* package has the same revision as the current one, it's not an update.
|
||||||
|
*
|
||||||
|
* @param replacementPackage The potential replacement package.
|
||||||
|
* @return True if the replacement package is a suitable update for this one.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean canBeUpdatedBy(Package replacementPackage) {
|
||||||
|
if (!super.canBeUpdatedBy(replacementPackage)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DocPackage newPkg = (DocPackage) replacementPackage;
|
||||||
|
return newPkg.getRevision() > this.getRevision() &&
|
||||||
|
newPkg.getApiLevel() >= this.getApiLevel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,23 @@ public abstract class Package implements IDescription {
|
|||||||
*/
|
*/
|
||||||
public abstract File getInstallFolder(String osSdkRoot);
|
public abstract File getInstallFolder(String osSdkRoot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes whether the given package is a suitable update for the current package.
|
||||||
|
* The base class method only checks that the {@link Package} class type is the same.
|
||||||
|
* Derived classes must add more specific checks, including the revision number.
|
||||||
|
* <p/>
|
||||||
|
* An update is just that: a new package that supersedes the current one. If the new
|
||||||
|
* package has the same revision as the current one, it's not an update.
|
||||||
|
*
|
||||||
|
* @param replacementPackage The potential replacement package.
|
||||||
|
* @return True if the replacement package is a suitable update for this one.
|
||||||
|
*/
|
||||||
|
public boolean canBeUpdatedBy(Package replacementPackage) {
|
||||||
|
return replacementPackage != null &&
|
||||||
|
replacementPackage.getClass() == this.getClass() &&
|
||||||
|
replacementPackage.getRevision() > this.getRevision();
|
||||||
|
}
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -111,4 +111,28 @@ public class PlatformPackage extends Package {
|
|||||||
// TODO find similar existing platform in platforms folder
|
// TODO find similar existing platform in platforms folder
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes whether the given platform package is a suitable update for the current package.
|
||||||
|
* The base method checks the class type.
|
||||||
|
* The platform package also tests that the version and API level are the same and
|
||||||
|
* the revision number is greater
|
||||||
|
* <p/>
|
||||||
|
* An update is just that: a new package that supersedes the current one. If the new
|
||||||
|
* package has the same revision as the current one, it's not an update.
|
||||||
|
*
|
||||||
|
* @param replacementPackage The potential replacement package.
|
||||||
|
* @return True if the replacement package is a suitable update for this one.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean canBeUpdatedBy(Package replacementPackage) {
|
||||||
|
if (!super.canBeUpdatedBy(replacementPackage)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformPackage newPkg = (PlatformPackage) replacementPackage;
|
||||||
|
return newPkg.getVersion().equalsIgnoreCase(this.getVersion()) &&
|
||||||
|
newPkg.getApiLevel() == this.getApiLevel() &&
|
||||||
|
newPkg.getRevision() > this.getRevision();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,16 @@ public class RepoSources {
|
|||||||
public RepoSources() {
|
public RepoSources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new source to the Sources list.
|
||||||
|
*/
|
||||||
public void add(RepoSource source) {
|
public void add(RepoSource source) {
|
||||||
mSources.add(source);
|
mSources.add(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sources list array. This is never null.
|
||||||
|
*/
|
||||||
public ArrayList<RepoSource> getSources() {
|
public ArrayList<RepoSource> getSources() {
|
||||||
return mSources;
|
return mSources;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,4 +88,25 @@ public class ToolPackage extends Package {
|
|||||||
public File getInstallFolder(String osSdkRoot) {
|
public File getInstallFolder(String osSdkRoot) {
|
||||||
return new File(osSdkRoot, SdkConstants.FD_TOOLS);
|
return new File(osSdkRoot, SdkConstants.FD_TOOLS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes whether the given tools package is a suitable update for the current package.
|
||||||
|
* The base method checks the class type.
|
||||||
|
* The tools package also tests that the revision number is greater.
|
||||||
|
* <p/>
|
||||||
|
* An update is just that: a new package that supersedes the current one. If the new
|
||||||
|
* package has the same revision as the current one, it's not an update.
|
||||||
|
*
|
||||||
|
* @param replacementPackage The potential replacement package.
|
||||||
|
* @return True if the replacement package is a suitable update for this one.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean canBeUpdatedBy(Package replacementPackage) {
|
||||||
|
if (!super.canBeUpdatedBy(replacementPackage)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolPackage newPkg = (ToolPackage) replacementPackage;
|
||||||
|
return newPkg.getRevision() > this.getRevision();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
|
|||||||
super(parent, SWT.BORDER);
|
super(parent, SWT.BORDER);
|
||||||
|
|
||||||
mUpdaterData = updaterData;
|
mUpdaterData = updaterData;
|
||||||
mUpdaterData.addListeners(this);
|
|
||||||
|
|
||||||
createContents(this);
|
createContents(this);
|
||||||
postCreate(); //$hide$
|
postCreate(); //$hide$
|
||||||
@@ -121,39 +120,39 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
|
|||||||
mContainerButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
|
mContainerButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
|
||||||
|
|
||||||
mUpdateButton = new Button(mContainerButtons, SWT.NONE);
|
mUpdateButton = new Button(mContainerButtons, SWT.NONE);
|
||||||
|
mUpdateButton.setText("Update All...");
|
||||||
mUpdateButton.addSelectionListener(new SelectionAdapter() {
|
mUpdateButton.addSelectionListener(new SelectionAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
onUpdateInstalledPackage(); //$hide$ (hide from SWT designer)
|
onUpdateInstalledPackage(); //$hide$ (hide from SWT designer)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mUpdateButton.setText("Update...");
|
|
||||||
|
|
||||||
mPlaceholder1 = new Label(mContainerButtons, SWT.NONE);
|
mPlaceholder1 = new Label(mContainerButtons, SWT.NONE);
|
||||||
mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
||||||
|
|
||||||
mDeleteButton = new Button(mContainerButtons, SWT.NONE);
|
mDeleteButton = new Button(mContainerButtons, SWT.NONE);
|
||||||
|
mDeleteButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
|
||||||
|
mDeleteButton.setText("Delete...");
|
||||||
mDeleteButton.addSelectionListener(new SelectionAdapter() {
|
mDeleteButton.addSelectionListener(new SelectionAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
onDeleteSelected(); //$hide$ (hide from SWT designer)
|
onDeleteSelected(); //$hide$ (hide from SWT designer)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mDeleteButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
|
|
||||||
mDeleteButton.setText("Delete...");
|
|
||||||
|
|
||||||
mPlaceholder2 = new Label(mContainerButtons, SWT.NONE);
|
mPlaceholder2 = new Label(mContainerButtons, SWT.NONE);
|
||||||
mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
||||||
|
|
||||||
mRefreshButton = new Button(mContainerButtons, SWT.NONE);
|
mRefreshButton = new Button(mContainerButtons, SWT.NONE);
|
||||||
|
mRefreshButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
||||||
|
mRefreshButton.setText("Refresh");
|
||||||
mRefreshButton.addSelectionListener(new SelectionAdapter() {
|
mRefreshButton.addSelectionListener(new SelectionAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
onRefreshSelected(); //$hide$ (hide from SWT designer)
|
onRefreshSelected(); //$hide$ (hide from SWT designer)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mRefreshButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
|
||||||
mRefreshButton.setText("Refresh");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createSdkLocation(Composite parent) {
|
private void createSdkLocation(Composite parent) {
|
||||||
@@ -199,6 +198,7 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
|
|||||||
* Called by the constructor right after {@link #createContents(Composite)}.
|
* Called by the constructor right after {@link #createContents(Composite)}.
|
||||||
*/
|
*/
|
||||||
private void postCreate() {
|
private void postCreate() {
|
||||||
|
mUpdaterData.addListeners(this);
|
||||||
adjustColumnsWidth();
|
adjustColumnsWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,13 +210,15 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
|
|||||||
*/
|
*/
|
||||||
private void adjustColumnsWidth() {
|
private void adjustColumnsWidth() {
|
||||||
// Add a listener to resize the column to the full width of the table
|
// Add a listener to resize the column to the full width of the table
|
||||||
mTablePackages.addControlListener(new ControlAdapter() {
|
ControlAdapter resizer = new ControlAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void controlResized(ControlEvent e) {
|
public void controlResized(ControlEvent e) {
|
||||||
Rectangle r = mTablePackages.getClientArea();
|
Rectangle r = mTablePackages.getClientArea();
|
||||||
mColumnPackages.setWidth(r.width);
|
mColumnPackages.setWidth(r.width);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
mTablePackages.addControlListener(resizer);
|
||||||
|
resizer.controlResized(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -239,9 +241,7 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onUpdateInstalledPackage() {
|
private void onUpdateInstalledPackage() {
|
||||||
if (mUpdaterData != null) {
|
mUpdaterData.updateAll();
|
||||||
mUpdaterData.reloadSdk();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDeleteSelected() {
|
private void onDeleteSelected() {
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
|
|||||||
super(parent, SWT.BORDER);
|
super(parent, SWT.BORDER);
|
||||||
|
|
||||||
mUpdaterData = updaterData;
|
mUpdaterData = updaterData;
|
||||||
mUpdaterData.addListeners(this);
|
|
||||||
|
|
||||||
createContents(this);
|
createContents(this);
|
||||||
postCreate(); //$hide$
|
postCreate(); //$hide$
|
||||||
@@ -188,6 +187,7 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
|
|||||||
* Called by the constructor right after {@link #createContents(Composite)}.
|
* Called by the constructor right after {@link #createContents(Composite)}.
|
||||||
*/
|
*/
|
||||||
private void postCreate() {
|
private void postCreate() {
|
||||||
|
mUpdaterData.addListeners(this);
|
||||||
adjustColumnsWidth();
|
adjustColumnsWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,13 +199,16 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
|
|||||||
*/
|
*/
|
||||||
private void adjustColumnsWidth() {
|
private void adjustColumnsWidth() {
|
||||||
// Add a listener to resize the column to the full width of the table
|
// Add a listener to resize the column to the full width of the table
|
||||||
mTreeSources.addControlListener(new ControlAdapter() {
|
ControlAdapter resizer = new ControlAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void controlResized(ControlEvent e) {
|
public void controlResized(ControlEvent e) {
|
||||||
Rectangle r = mTreeSources.getClientArea();
|
Rectangle r = mTreeSources.getClientArea();
|
||||||
mColumnSource.setWidth(r.width);
|
mColumnSource.setWidth(r.width);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
mTreeSources.addControlListener(resizer);
|
||||||
|
resizer.controlResized(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,7 +306,7 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
|
|||||||
|
|
||||||
private void onRefreshSelected() {
|
private void onRefreshSelected() {
|
||||||
if (mUpdaterData != null) {
|
if (mUpdaterData != null) {
|
||||||
mUpdaterData.refreshSources(false /*forceFetching*/, null /*monitor*/);
|
mUpdaterData.refreshSources(false /*forceFetching*/);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,529 @@
|
|||||||
|
/*
|
||||||
|
* 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.internal.repository.Archive;
|
||||||
|
|
||||||
|
import org.eclipse.jface.viewers.CheckStateChangedEvent;
|
||||||
|
import org.eclipse.jface.viewers.CheckboxTableViewer;
|
||||||
|
import org.eclipse.jface.viewers.ICheckStateListener;
|
||||||
|
import org.eclipse.jface.viewers.ISelection;
|
||||||
|
import org.eclipse.jface.viewers.IStructuredContentProvider;
|
||||||
|
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||||
|
import org.eclipse.jface.viewers.LabelProvider;
|
||||||
|
import org.eclipse.jface.viewers.StructuredSelection;
|
||||||
|
import org.eclipse.jface.viewers.Viewer;
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.custom.SashForm;
|
||||||
|
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.events.ShellAdapter;
|
||||||
|
import org.eclipse.swt.events.ShellEvent;
|
||||||
|
import org.eclipse.swt.graphics.Image;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
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.Dialog;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.swt.widgets.Group;
|
||||||
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
import org.eclipse.swt.widgets.Table;
|
||||||
|
import org.eclipse.swt.widgets.TableColumn;
|
||||||
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements an {@link UpdateChooserDialog}.
|
||||||
|
*/
|
||||||
|
final class UpdateChooserDialog extends Dialog {
|
||||||
|
|
||||||
|
/** Last dialog size for this session. */
|
||||||
|
private static Point sLastSize;
|
||||||
|
private boolean mCompleted;
|
||||||
|
private final Map<Archive, Archive> mNewToOldArchiveMap;
|
||||||
|
private boolean mLicenseAcceptAll;
|
||||||
|
private boolean mInternalLicenseRadioUpdate;
|
||||||
|
private ArrayList<Archive> mResult = new ArrayList<Archive>();
|
||||||
|
|
||||||
|
// UI fields
|
||||||
|
private Shell mDialogShell;
|
||||||
|
private SashForm mSashForm;
|
||||||
|
private Composite mPackageRootComposite;
|
||||||
|
private Button mCancelButton;
|
||||||
|
private Button mInstallButton;
|
||||||
|
private CheckboxTableViewer mTableViewPackage;
|
||||||
|
private Table mTablePackage;
|
||||||
|
private TableColumn mTableColum;
|
||||||
|
private Text mPackageText;
|
||||||
|
private Button mLicenseRadioAccept;
|
||||||
|
private Button mLicenseRadioRefuse;
|
||||||
|
private Button mLicenseRadioAcceptAll;
|
||||||
|
private Group mPackageTextGroup;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the dialog.
|
||||||
|
* @param parent Parent container
|
||||||
|
* @param newToOldUpdates The map [new archive => old archive] of potential updates
|
||||||
|
*/
|
||||||
|
public UpdateChooserDialog(Shell parent, Map<Archive, Archive> newToOldUpdates) {
|
||||||
|
super(parent, SWT.APPLICATION_MODAL);
|
||||||
|
|
||||||
|
mNewToOldArchiveMap = new TreeMap<Archive, Archive>(new Comparator<Archive>() {
|
||||||
|
public int compare(Archive a1, Archive a2) {
|
||||||
|
// The items are archive but what we show are packages so we'll
|
||||||
|
// sort of packages short descriptions
|
||||||
|
String desc1 = a1.getParentPackage().getShortDescription();
|
||||||
|
String desc2 = a2.getParentPackage().getShortDescription();
|
||||||
|
return desc1.compareTo(desc2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mNewToOldArchiveMap.putAll(newToOldUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the results, i.e. the list of selected new archives to install.
|
||||||
|
* The list is always non null. It is empty when cancel is selected or when
|
||||||
|
* all potential updates have been refused.
|
||||||
|
*/
|
||||||
|
public Collection<Archive> getResult() {
|
||||||
|
return mResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the dialog and blocks till it gets closed
|
||||||
|
*/
|
||||||
|
public void open() {
|
||||||
|
createContents();
|
||||||
|
positionShell(); //$hide$ (hide from SWT designer)
|
||||||
|
mDialogShell.open();
|
||||||
|
mDialogShell.layout();
|
||||||
|
|
||||||
|
postCreate(); //$hide$ (hide from SWT designer)
|
||||||
|
|
||||||
|
Display display = getParent().getDisplay();
|
||||||
|
while (!mDialogShell.isDisposed() && !mCompleted) {
|
||||||
|
if (!display.readAndDispatch()) {
|
||||||
|
display.sleep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mDialogShell.isDisposed()) {
|
||||||
|
mDialogShell.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create contents of the dialog.
|
||||||
|
*/
|
||||||
|
private void createContents() {
|
||||||
|
mDialogShell = new Shell(getParent(), SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MIN | SWT.MAX);
|
||||||
|
mDialogShell.addShellListener(new ShellAdapter() {
|
||||||
|
@Override
|
||||||
|
public void shellClosed(ShellEvent e) {
|
||||||
|
onShellClosed(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mDialogShell.setLayout(new GridLayout(3, false/*makeColumnsEqual*/));
|
||||||
|
mDialogShell.setSize(600, 400);
|
||||||
|
mDialogShell.setText(getText());
|
||||||
|
|
||||||
|
// Sash form
|
||||||
|
mSashForm = new SashForm(mDialogShell, SWT.NONE);
|
||||||
|
mSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
|
||||||
|
|
||||||
|
|
||||||
|
// Left part of Sash Form
|
||||||
|
|
||||||
|
mTableViewPackage = CheckboxTableViewer.newCheckList(mSashForm,
|
||||||
|
SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE);
|
||||||
|
mTablePackage = mTableViewPackage.getTable();
|
||||||
|
mTablePackage.setHeaderVisible(false);
|
||||||
|
|
||||||
|
mTablePackage.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
onPackageSelected(); //$hide$
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void widgetDefaultSelected(SelectionEvent e) {
|
||||||
|
onPackageDoubleClick();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mTableViewPackage.addCheckStateListener(new ICheckStateListener() {
|
||||||
|
public void checkStateChanged(CheckStateChangedEvent event) {
|
||||||
|
onPackageChecked(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mTableColum = new TableColumn(mTablePackage, SWT.NONE);
|
||||||
|
mTableColum.setWidth(100);
|
||||||
|
mTableColum.setText("Packages");
|
||||||
|
|
||||||
|
|
||||||
|
// Right part of Sash form
|
||||||
|
mPackageRootComposite = new Composite(mSashForm, SWT.NONE);
|
||||||
|
mPackageRootComposite.setLayout(new GridLayout(4, false/*makeColumnsEqual*/));
|
||||||
|
|
||||||
|
mPackageTextGroup = new Group(mPackageRootComposite, SWT.NONE);
|
||||||
|
mPackageTextGroup.setText("Package Description && License");
|
||||||
|
mPackageTextGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
|
||||||
|
mPackageTextGroup.setLayout(new GridLayout(1, false/*makeColumnsEqual*/));
|
||||||
|
|
||||||
|
mPackageText = new Text(mPackageTextGroup,
|
||||||
|
SWT.MULTI | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL);
|
||||||
|
mPackageText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
|
||||||
|
|
||||||
|
mLicenseRadioAccept = new Button(mPackageRootComposite, SWT.RADIO);
|
||||||
|
mLicenseRadioAccept.setText("Accept");
|
||||||
|
mLicenseRadioAccept.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
|
||||||
|
mLicenseRadioAccept.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
onLicenseRadioSelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mLicenseRadioRefuse = new Button(mPackageRootComposite, SWT.RADIO);
|
||||||
|
mLicenseRadioRefuse.setText("Refuse");
|
||||||
|
mLicenseRadioRefuse.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
|
||||||
|
mLicenseRadioRefuse.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
onLicenseRadioSelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Label placeholder = new Label(mPackageRootComposite, SWT.NONE);
|
||||||
|
placeholder.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
||||||
|
|
||||||
|
mLicenseRadioAcceptAll = new Button(mPackageRootComposite, SWT.RADIO);
|
||||||
|
mLicenseRadioAcceptAll.setText("Accept All");
|
||||||
|
mLicenseRadioAcceptAll.setLayoutData(
|
||||||
|
new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
|
||||||
|
mLicenseRadioAcceptAll.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
onLicenseRadioSelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mSashForm.setWeights(new int[] {200, 300});
|
||||||
|
|
||||||
|
// Bottom buttons
|
||||||
|
placeholder = new Label(mDialogShell, SWT.NONE);
|
||||||
|
placeholder.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
|
||||||
|
|
||||||
|
mInstallButton = new Button(mDialogShell, SWT.PUSH);
|
||||||
|
mInstallButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
||||||
|
mInstallButton.setText("Install Selected");
|
||||||
|
mInstallButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
onInstallSelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mCancelButton = new Button(mDialogShell, SWT.PUSH);
|
||||||
|
mCancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
||||||
|
mCancelButton.setText("Cancel");
|
||||||
|
mCancelButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
onCancelSelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- End of UI, Start of internal logic ----------
|
||||||
|
// Hide everything down-below from SWT designer
|
||||||
|
//$hide>>$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the thread that runs the task.
|
||||||
|
* This is deferred till the UI is created.
|
||||||
|
*/
|
||||||
|
private void postCreate() {
|
||||||
|
// Fill the list with the replacement packages
|
||||||
|
mTableViewPackage.setLabelProvider(new NewArchivesLabelProvider());
|
||||||
|
mTableViewPackage.setContentProvider(new NewArchivesContentProvider());
|
||||||
|
mTableViewPackage.setInput(mNewToOldArchiveMap);
|
||||||
|
|
||||||
|
adjustColumnsWidth();
|
||||||
|
|
||||||
|
// select first item
|
||||||
|
mTablePackage.select(0);
|
||||||
|
onPackageSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener to adjust the columns width when the parent is resized.
|
||||||
|
* <p/>
|
||||||
|
* If we need something more fancy, we might want to use this:
|
||||||
|
* http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet77.java?view=co
|
||||||
|
*/
|
||||||
|
private void adjustColumnsWidth() {
|
||||||
|
// Add a listener to resize the column to the full width of the table
|
||||||
|
ControlAdapter resizer = new ControlAdapter() {
|
||||||
|
@Override
|
||||||
|
public void controlResized(ControlEvent e) {
|
||||||
|
Rectangle r = mTablePackage.getClientArea();
|
||||||
|
mTableColum.setWidth(r.width);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mTablePackage.addControlListener(resizer);
|
||||||
|
resizer.controlResized(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked when the shell is closed either by clicking the close button
|
||||||
|
* on by calling shell.close().
|
||||||
|
* Captures the window size before closing this.
|
||||||
|
*/
|
||||||
|
private void onShellClosed(ShellEvent e) {
|
||||||
|
sLastSize = mDialogShell.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centers the dialog in its parent shell.
|
||||||
|
*/
|
||||||
|
private void positionShell() {
|
||||||
|
// Centers the dialog in its parent shell
|
||||||
|
Shell child = mDialogShell;
|
||||||
|
Shell parent = getParent();
|
||||||
|
if (child != null && parent != null) {
|
||||||
|
|
||||||
|
// get the parent client area with a location relative to the display
|
||||||
|
Rectangle parentArea = parent.getClientArea();
|
||||||
|
Point parentLoc = parent.getLocation();
|
||||||
|
int px = parentLoc.x;
|
||||||
|
int py = parentLoc.y;
|
||||||
|
int pw = parentArea.width;
|
||||||
|
int ph = parentArea.height;
|
||||||
|
|
||||||
|
// Reuse the last size if there's one, otherwise use the default
|
||||||
|
Point childSize = sLastSize != null ? sLastSize : child.getSize();
|
||||||
|
int cw = childSize.x;
|
||||||
|
int ch = childSize.y;
|
||||||
|
|
||||||
|
child.setLocation(px + (pw - cw) / 2, py + (ph - ch) / 2);
|
||||||
|
child.setSize(cw, ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked when the Install button is selected. Fills {@link #mResult} and
|
||||||
|
* completes the dialog.
|
||||||
|
*/
|
||||||
|
private void onInstallSelected() {
|
||||||
|
|
||||||
|
// get list of checked items
|
||||||
|
Object[] checked = mTableViewPackage.getCheckedElements();
|
||||||
|
|
||||||
|
if (checked != null) {
|
||||||
|
for (Object obj : checked) {
|
||||||
|
mResult.add((Archive) obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mCompleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked when the Cancel button is selected.
|
||||||
|
*/
|
||||||
|
private void onCancelSelected() {
|
||||||
|
mCompleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked when a package item is selected in the list.
|
||||||
|
*/
|
||||||
|
private void onPackageSelected() {
|
||||||
|
Archive a = getSelectedArchive();
|
||||||
|
displayInformation(a);
|
||||||
|
updateLicenceRadios(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the currently selected Archive or null. */
|
||||||
|
private Archive getSelectedArchive() {
|
||||||
|
ISelection sel = mTableViewPackage.getSelection();
|
||||||
|
if (sel instanceof IStructuredSelection) {
|
||||||
|
Object elem = ((IStructuredSelection) sel).getFirstElement();
|
||||||
|
if (elem instanceof Archive) {
|
||||||
|
return (Archive) elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSelectedAchive(Archive a) {
|
||||||
|
if (a == null) {
|
||||||
|
mTablePackage.deselectAll();
|
||||||
|
} else {
|
||||||
|
IStructuredSelection sel = new StructuredSelection(a);
|
||||||
|
mTableViewPackage.setSelection(sel, true /*reveal*/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayInformation(Archive a) {
|
||||||
|
if (a == null) {
|
||||||
|
mPackageText.setText("Please select a package.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
Archive aold = mNewToOldArchiveMap.get(a);
|
||||||
|
if (aold != null) {
|
||||||
|
sb.append("*** Existing Package Description:\n");
|
||||||
|
sb.append(aold.getParentPackage().getLongDescription()).append("\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("*** New Package Description:\n");
|
||||||
|
sb.append(a.getParentPackage().getLongDescription()).append("\n\n");
|
||||||
|
|
||||||
|
sb.append("\n*** Archive Description:\n");
|
||||||
|
sb.append(a.getLongDescription()).append("\n");
|
||||||
|
|
||||||
|
sb.append("\n*** Package License:\n");
|
||||||
|
sb.append(a.getParentPackage().getLicense()).append("\n");
|
||||||
|
|
||||||
|
mPackageText.setText(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLicenceRadios(Archive a) {
|
||||||
|
if (mInternalLicenseRadioUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mInternalLicenseRadioUpdate = true;
|
||||||
|
|
||||||
|
if (mLicenseAcceptAll) {
|
||||||
|
mLicenseRadioAcceptAll.setSelection(true);
|
||||||
|
mLicenseRadioAccept.setSelection(false);
|
||||||
|
mLicenseRadioRefuse.setSelection(false);
|
||||||
|
} else {
|
||||||
|
boolean accept = mTableViewPackage.getChecked(a);
|
||||||
|
|
||||||
|
mLicenseRadioAcceptAll.setSelection(false);
|
||||||
|
mLicenseRadioAccept.setSelection(accept);
|
||||||
|
mLicenseRadioRefuse.setSelection(!accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
mInternalLicenseRadioUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked when one of the radio license buttons is selected.
|
||||||
|
*
|
||||||
|
* - accept/refuse: toggle, update item checkbox
|
||||||
|
* - accept all: set accept-all, check all items
|
||||||
|
*/
|
||||||
|
private void onLicenseRadioSelected() {
|
||||||
|
if (mInternalLicenseRadioUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mInternalLicenseRadioUpdate = true;
|
||||||
|
|
||||||
|
Archive a = getSelectedArchive();
|
||||||
|
|
||||||
|
if (!mLicenseAcceptAll && mLicenseRadioAcceptAll.getSelection()) {
|
||||||
|
// Accept all has been switched on. Mark all packages as accepted
|
||||||
|
mLicenseAcceptAll = true;
|
||||||
|
mTableViewPackage.setAllChecked(true);
|
||||||
|
|
||||||
|
} else if (mLicenseRadioAccept.getSelection()) {
|
||||||
|
// Accept only this one
|
||||||
|
mLicenseAcceptAll = false;
|
||||||
|
mTableViewPackage.setChecked(a, true);
|
||||||
|
|
||||||
|
} else if (mLicenseRadioRefuse.getSelection()) {
|
||||||
|
// Refuse only this one
|
||||||
|
mLicenseAcceptAll = false;
|
||||||
|
mTableViewPackage.setChecked(a, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
mInternalLicenseRadioUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked when a package item is double-clicked in the list.
|
||||||
|
*/
|
||||||
|
private void onPackageDoubleClick() {
|
||||||
|
Archive a = getSelectedArchive();
|
||||||
|
|
||||||
|
mTableViewPackage.setChecked(a, !mTableViewPackage.getChecked(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onPackageChecked(CheckStateChangedEvent event) {
|
||||||
|
Object e = event.getElement();
|
||||||
|
if (e instanceof Archive) {
|
||||||
|
Archive a = (Archive) e;
|
||||||
|
|
||||||
|
// select it
|
||||||
|
mLicenseAcceptAll = false;
|
||||||
|
setSelectedAchive(a);
|
||||||
|
updateLicenceRadios(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NewArchivesLabelProvider extends LabelProvider {
|
||||||
|
@Override
|
||||||
|
public Image getImage(Object element) {
|
||||||
|
return super.getImage(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText(Object element) {
|
||||||
|
if (element instanceof Archive) {
|
||||||
|
return ((Archive) element).getParentPackage().getShortDescription();
|
||||||
|
}
|
||||||
|
return super.getText(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NewArchivesContentProvider implements IStructuredContentProvider {
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
|
// Ignore. The input is always mNewArchives
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getElements(Object inputElement) {
|
||||||
|
return mNewToOldArchiveMap.keySet().toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of hiding from SWT Designer
|
||||||
|
//$hide<<$
|
||||||
|
}
|
||||||
@@ -25,14 +25,18 @@ import com.android.sdklib.internal.repository.ITask;
|
|||||||
import com.android.sdklib.internal.repository.ITaskFactory;
|
import com.android.sdklib.internal.repository.ITaskFactory;
|
||||||
import com.android.sdklib.internal.repository.ITaskMonitor;
|
import com.android.sdklib.internal.repository.ITaskMonitor;
|
||||||
import com.android.sdklib.internal.repository.LocalSdkParser;
|
import com.android.sdklib.internal.repository.LocalSdkParser;
|
||||||
|
import com.android.sdklib.internal.repository.Package;
|
||||||
import com.android.sdklib.internal.repository.RepoSource;
|
import com.android.sdklib.internal.repository.RepoSource;
|
||||||
import com.android.sdklib.internal.repository.RepoSources;
|
import com.android.sdklib.internal.repository.RepoSources;
|
||||||
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
|
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
|
||||||
|
|
||||||
import org.eclipse.swt.widgets.Display;
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data shared between {@link UpdaterWindowImpl} and its pages.
|
* Data shared between {@link UpdaterWindowImpl} and its pages.
|
||||||
@@ -59,7 +63,8 @@ class UpdaterData {
|
|||||||
|
|
||||||
private final ArrayList<ISdkListener> mListeners = new ArrayList<ISdkListener>();
|
private final ArrayList<ISdkListener> mListeners = new ArrayList<ISdkListener>();
|
||||||
|
|
||||||
private Display mDisplay;
|
/** @deprecated */private Display mDisplay; // TODO remove
|
||||||
|
private Shell mWindowShell;
|
||||||
|
|
||||||
public interface ISdkListener {
|
public interface ISdkListener {
|
||||||
void onSdkChange();
|
void onSdkChange();
|
||||||
@@ -72,6 +77,8 @@ class UpdaterData {
|
|||||||
initSdk();
|
initSdk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----- getters, setters ----
|
||||||
|
|
||||||
public void setOsSdkRoot(String osSdkRoot) {
|
public void setOsSdkRoot(String osSdkRoot) {
|
||||||
if (mOsSdkRoot == null || mOsSdkRoot.equals(osSdkRoot) == false) {
|
if (mOsSdkRoot == null || mOsSdkRoot.equals(osSdkRoot) == false) {
|
||||||
mOsSdkRoot = osSdkRoot;
|
mOsSdkRoot = osSdkRoot;
|
||||||
@@ -153,6 +160,35 @@ class UpdaterData {
|
|||||||
mListeners.remove(listener);
|
mListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setWindowShell(Shell windowShell) {
|
||||||
|
mWindowShell = windowShell;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Shell getWindowShell() {
|
||||||
|
return mWindowShell;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the {@link SdkManager} and the {@link AvdManager}.
|
||||||
|
*/
|
||||||
|
private void initSdk() {
|
||||||
|
mSdkManager = SdkManager.createManager(mOsSdkRoot, mSdkLog);
|
||||||
|
try {
|
||||||
|
mAvdManager = null; // remove the old one if needed.
|
||||||
|
mAvdManager = new AvdManager(mSdkManager, mSdkLog);
|
||||||
|
} catch (AndroidLocationException e) {
|
||||||
|
mSdkLog.error(e, "Unable to read AVDs");
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify adapters/parsers
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// notify listeners.
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads the SDK content (targets).
|
* Reloads the SDK content (targets).
|
||||||
* <p/> This also reloads the AVDs in case their status changed.
|
* <p/> This also reloads the AVDs in case their status changed.
|
||||||
@@ -288,18 +324,17 @@ class UpdaterData {
|
|||||||
public void updateAll() {
|
public void updateAll() {
|
||||||
assert mTaskFactory != null;
|
assert mTaskFactory != null;
|
||||||
|
|
||||||
mTaskFactory.start("Update Archives", new ITask() {
|
refreshSources(true);
|
||||||
public void run(ITaskMonitor monitor) {
|
|
||||||
monitor.setProgressMax(3);
|
|
||||||
|
|
||||||
monitor.setDescription("Refresh sources");
|
final Map<Archive, Archive> updates = findUpdates();
|
||||||
refreshSources(true, monitor.createSubMonitor(1));
|
|
||||||
|
|
||||||
// TODO compare available vs local
|
UpdateChooserDialog dialog = new UpdateChooserDialog(getWindowShell(), updates);
|
||||||
// TODO suggest update packages to user (also validate license click-through)
|
dialog.open();
|
||||||
// TODO install selected packages
|
|
||||||
}
|
Collection<Archive> result = dialog.getResult();
|
||||||
});
|
if (result != null && result.size() > 0) {
|
||||||
|
installArchives(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -307,15 +342,15 @@ class UpdaterData {
|
|||||||
* or as a UI callback on the remote page "Refresh" button (in which case the monitor is
|
* or as a UI callback on the remote page "Refresh" button (in which case the monitor is
|
||||||
* null and a new task should be created.)
|
* null and a new task should be created.)
|
||||||
*
|
*
|
||||||
* @param forceFetching When true, load sources that haven't been loaded yet. When
|
* @param forceFetching When true, load sources that haven't been loaded yet.
|
||||||
* false, only refresh sources that have been loaded yet.
|
* When false, only refresh sources that have been loaded yet.
|
||||||
*/
|
*/
|
||||||
public void refreshSources(final boolean forceFetching, ITaskMonitor monitor) {
|
public void refreshSources(final boolean forceFetching) {
|
||||||
assert mTaskFactory != null;
|
assert mTaskFactory != null;
|
||||||
|
|
||||||
final boolean forceHttp = getSettingsController().getForceHttp();
|
final boolean forceHttp = getSettingsController().getForceHttp();
|
||||||
|
|
||||||
ITask task = new ITask() {
|
mTaskFactory.start("Refresh Sources",new ITask() {
|
||||||
public void run(ITaskMonitor monitor) {
|
public void run(ITaskMonitor monitor) {
|
||||||
ArrayList<RepoSource> sources = mSources.getSources();
|
ArrayList<RepoSource> sources = mSources.getSources();
|
||||||
monitor.setProgressMax(sources.size());
|
monitor.setProgressMax(sources.size());
|
||||||
@@ -324,34 +359,87 @@ class UpdaterData {
|
|||||||
source.load(monitor.createSubMonitor(1), forceHttp);
|
source.load(monitor.createSubMonitor(1), forceHttp);
|
||||||
}
|
}
|
||||||
monitor.incProgress(1);
|
monitor.incProgress(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (monitor != null) {
|
|
||||||
task.run(monitor);
|
|
||||||
} else {
|
|
||||||
mTaskFactory.start("Refresh Sources", task);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the {@link SdkManager} and the {@link AvdManager}.
|
* Check the local archives vs the remote available packages to find potential updates.
|
||||||
|
* Return a map [remote archive => local archive] of suitable update candidates.
|
||||||
|
* Returns null if there's an unexpected error. Otherwise returns a map that can be
|
||||||
|
* empty but not null.
|
||||||
*/
|
*/
|
||||||
private void initSdk() {
|
private Map<Archive, Archive> findUpdates() {
|
||||||
mSdkManager = SdkManager.createManager(mOsSdkRoot, mSdkLog);
|
// Map [remote archive => local archive] of suitable update candidates
|
||||||
try {
|
Map<Archive, Archive> result = new HashMap<Archive, Archive>();
|
||||||
mAvdManager = null; // remove the old one if needed.
|
|
||||||
mAvdManager = new AvdManager(mSdkManager, mSdkLog);
|
// First go thru all sources and make a local list of all available archives
|
||||||
} catch (AndroidLocationException e) {
|
// sorted by package class.
|
||||||
mSdkLog.error(e, "Unable to read AVDs");
|
HashMap<Class<? extends Package>, ArrayList<Archive>> availPkgs =
|
||||||
|
new HashMap<Class<? extends Package>, ArrayList<Archive>>();
|
||||||
|
|
||||||
|
ArrayList<RepoSource> remoteSources = getSources().getSources();
|
||||||
|
|
||||||
|
for (RepoSource remoteSrc : remoteSources) {
|
||||||
|
Package[] remotePkgs = remoteSrc.getPackages();
|
||||||
|
if (remotePkgs != null) {
|
||||||
|
for (Package remotePkg : remotePkgs) {
|
||||||
|
Class<? extends Package> clazz = remotePkg.getClass();
|
||||||
|
|
||||||
|
ArrayList<Archive> list = availPkgs.get(clazz);
|
||||||
|
if (list == null) {
|
||||||
|
availPkgs.put(clazz, list = new ArrayList<Archive>());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Archive a : remotePkg.getArchives()) {
|
||||||
|
// Only add compatible archives
|
||||||
|
if (a.isCompatible()) {
|
||||||
|
list.add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify adapters/parsers
|
Package[] localPkgs = getLocalSdkParser().getPackages();
|
||||||
// TODO
|
if (localPkgs == null) {
|
||||||
|
// This is unexpected. The local sdk parser should have been called first.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// notify listeners.
|
for (Package localPkg : localPkgs) {
|
||||||
notifyListeners();
|
// get the available archive list for this package type
|
||||||
|
ArrayList<Archive> list = availPkgs.get(localPkg.getClass());
|
||||||
|
|
||||||
|
// if this list is empty, we'll never find anything that matches
|
||||||
|
if (list == null || list.size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// local packages should have one archive at most
|
||||||
|
Archive[] localArchives = localPkg.getArchives();
|
||||||
|
if (localArchives != null && localArchives.length > 0) {
|
||||||
|
Archive localArchive = localArchives[0];
|
||||||
|
// only consider archive compatible with the current platform
|
||||||
|
if (localArchive != null && localArchive.isCompatible()) {
|
||||||
|
|
||||||
|
// We checked all this archive stuff because that's what eventually gets
|
||||||
|
// installed, but the "update" mechanism really works on packages. So now
|
||||||
|
// the real question: is there a remote package that can update this
|
||||||
|
// local package?
|
||||||
|
|
||||||
|
for (Archive availArchive : list) {
|
||||||
|
if (localPkg.canBeUpdatedBy(availArchive.getParentPackage())) {
|
||||||
|
// Found one!
|
||||||
|
result.put(availArchive, localArchive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public class UpdaterWindowImpl {
|
|||||||
mAvdManagerPage = new AvdManagerPage(mPagesRootComposite, mUpdaterData);
|
mAvdManagerPage = new AvdManagerPage(mPagesRootComposite, mUpdaterData);
|
||||||
mLocalPackagePage = new LocalPackagesPage(mPagesRootComposite, mUpdaterData);
|
mLocalPackagePage = new LocalPackagesPage(mPagesRootComposite, mUpdaterData);
|
||||||
mRemotePackagesPage = new RemotePackagesPage(mPagesRootComposite, mUpdaterData);
|
mRemotePackagesPage = new RemotePackagesPage(mPagesRootComposite, mUpdaterData);
|
||||||
|
|
||||||
mSashForm.setWeights(new int[] {150, 576});
|
mSashForm.setWeights(new int[] {150, 576});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +201,7 @@ public class UpdaterWindowImpl {
|
|||||||
* This creates the pages, selects the first one, setup sources and scan for local folders.
|
* This creates the pages, selects the first one, setup sources and scan for local folders.
|
||||||
*/
|
*/
|
||||||
private void firstInit() {
|
private void firstInit() {
|
||||||
|
mUpdaterData.setWindowShell(getShell());
|
||||||
mTaskFactory = new ProgressTaskFactory(getShell());
|
mTaskFactory = new ProgressTaskFactory(getShell());
|
||||||
mUpdaterData.setTaskFactory(mTaskFactory);
|
mUpdaterData.setTaskFactory(mTaskFactory);
|
||||||
mUpdaterData.setImageFactory(new ImageFactory(getShell().getDisplay()));
|
mUpdaterData.setImageFactory(new ImageFactory(getShell().getDisplay()));
|
||||||
|
|||||||
Reference in New Issue
Block a user