SDK Updater: update all existing local archives, license click through.

This commit is contained in:
Raphael
2009-06-13 22:42:31 -07:00
parent 31d55c618e
commit e073146af3
11 changed files with 788 additions and 50 deletions

View File

@@ -190,6 +190,9 @@ public class AddonPackage extends Package {
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.replaceAll("[^a-zA-Z0-9_-]+", "_"); // $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
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();
}
}

View File

@@ -104,4 +104,27 @@ public class DocPackage extends Package {
public File getInstallFolder(String osSdkRoot) {
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();
}
}

View File

@@ -202,6 +202,23 @@ public abstract class Package implements IDescription {
*/
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();
}
//---
/**

View File

@@ -111,4 +111,28 @@ public class PlatformPackage extends Package {
// TODO find similar existing platform in platforms 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();
}
}

View File

@@ -28,10 +28,16 @@ public class RepoSources {
public RepoSources() {
}
/**
* Adds a new source to the Sources list.
*/
public void add(RepoSource source) {
mSources.add(source);
}
/**
* Returns the sources list array. This is never null.
*/
public ArrayList<RepoSource> getSources() {
return mSources;
}

View File

@@ -88,4 +88,25 @@ public class ToolPackage extends Package {
public File getInstallFolder(String osSdkRoot) {
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();
}
}

View File

@@ -81,7 +81,6 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
super(parent, SWT.BORDER);
mUpdaterData = updaterData;
mUpdaterData.addListeners(this);
createContents(this);
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));
mUpdateButton = new Button(mContainerButtons, SWT.NONE);
mUpdateButton.setText("Update All...");
mUpdateButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
onUpdateInstalledPackage(); //$hide$ (hide from SWT designer)
}
});
mUpdateButton.setText("Update...");
mPlaceholder1 = new Label(mContainerButtons, SWT.NONE);
mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
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() {
@Override
public void widgetSelected(SelectionEvent e) {
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.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
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() {
@Override
public void widgetSelected(SelectionEvent e) {
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) {
@@ -199,6 +198,7 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
* Called by the constructor right after {@link #createContents(Composite)}.
*/
private void postCreate() {
mUpdaterData.addListeners(this);
adjustColumnsWidth();
}
@@ -210,13 +210,15 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
*/
private void adjustColumnsWidth() {
// Add a listener to resize the column to the full width of the table
mTablePackages.addControlListener(new ControlAdapter() {
ControlAdapter resizer = new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
Rectangle r = mTablePackages.getClientArea();
mColumnPackages.setWidth(r.width);
}
});
};
mTablePackages.addControlListener(resizer);
resizer.controlResized(null);
}
/**
@@ -239,9 +241,7 @@ public class LocalPackagesPage extends Composite implements ISdkListener {
}
private void onUpdateInstalledPackage() {
if (mUpdaterData != null) {
mUpdaterData.reloadSdk();
}
mUpdaterData.updateAll();
}
private void onDeleteSelected() {

View File

@@ -86,7 +86,6 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
super(parent, SWT.BORDER);
mUpdaterData = updaterData;
mUpdaterData.addListeners(this);
createContents(this);
postCreate(); //$hide$
@@ -188,6 +187,7 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
* Called by the constructor right after {@link #createContents(Composite)}.
*/
private void postCreate() {
mUpdaterData.addListeners(this);
adjustColumnsWidth();
}
@@ -199,13 +199,16 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
*/
private void adjustColumnsWidth() {
// Add a listener to resize the column to the full width of the table
mTreeSources.addControlListener(new ControlAdapter() {
ControlAdapter resizer = new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
Rectangle r = mTreeSources.getClientArea();
mColumnSource.setWidth(r.width);
}
});
};
mTreeSources.addControlListener(resizer);
resizer.controlResized(null);
}
/**
@@ -303,7 +306,7 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
private void onRefreshSelected() {
if (mUpdaterData != null) {
mUpdaterData.refreshSources(false /*forceFetching*/, null /*monitor*/);
mUpdaterData.refreshSources(false /*forceFetching*/);
}
}

View File

@@ -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<<$
}

View File

@@ -25,14 +25,18 @@ import com.android.sdklib.internal.repository.ITask;
import com.android.sdklib.internal.repository.ITaskFactory;
import com.android.sdklib.internal.repository.ITaskMonitor;
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.RepoSources;
import com.android.sdkuilib.internal.repository.icons.ImageFactory;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* Data shared between {@link UpdaterWindowImpl} and its pages.
@@ -59,7 +63,8 @@ class UpdaterData {
private final ArrayList<ISdkListener> mListeners = new ArrayList<ISdkListener>();
private Display mDisplay;
/** @deprecated */private Display mDisplay; // TODO remove
private Shell mWindowShell;
public interface ISdkListener {
void onSdkChange();
@@ -72,6 +77,8 @@ class UpdaterData {
initSdk();
}
// ----- getters, setters ----
public void setOsSdkRoot(String osSdkRoot) {
if (mOsSdkRoot == null || mOsSdkRoot.equals(osSdkRoot) == false) {
mOsSdkRoot = osSdkRoot;
@@ -153,6 +160,35 @@ class UpdaterData {
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).
* <p/> This also reloads the AVDs in case their status changed.
@@ -288,18 +324,17 @@ class UpdaterData {
public void updateAll() {
assert mTaskFactory != null;
mTaskFactory.start("Update Archives", new ITask() {
public void run(ITaskMonitor monitor) {
monitor.setProgressMax(3);
refreshSources(true);
monitor.setDescription("Refresh sources");
refreshSources(true, monitor.createSubMonitor(1));
final Map<Archive, Archive> updates = findUpdates();
// TODO compare available vs local
// TODO suggest update packages to user (also validate license click-through)
// TODO install selected packages
UpdateChooserDialog dialog = new UpdateChooserDialog(getWindowShell(), updates);
dialog.open();
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
* null and a new task should be created.)
*
* @param forceFetching When true, load sources that haven't been loaded yet. When
* false, only refresh sources that have been loaded yet.
* @param forceFetching When true, load sources that haven't 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;
final boolean forceHttp = getSettingsController().getForceHttp();
ITask task = new ITask() {
mTaskFactory.start("Refresh Sources",new ITask() {
public void run(ITaskMonitor monitor) {
ArrayList<RepoSource> sources = mSources.getSources();
monitor.setProgressMax(sources.size());
@@ -324,34 +359,87 @@ class UpdaterData {
source.load(monitor.createSubMonitor(1), forceHttp);
}
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() {
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");
private Map<Archive, Archive> findUpdates() {
// Map [remote archive => local archive] of suitable update candidates
Map<Archive, Archive> result = new HashMap<Archive, Archive>();
// First go thru all sources and make a local list of all available archives
// sorted by package class.
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>());
}
// notify adapters/parsers
// TODO
for (Archive a : remotePkg.getArchives()) {
// Only add compatible archives
if (a.isCompatible()) {
list.add(a);
}
}
}
}
}
// notify listeners.
notifyListeners();
Package[] localPkgs = getLocalSdkParser().getPackages();
if (localPkgs == null) {
// This is unexpected. The local sdk parser should have been called first.
return null;
}
for (Package localPkg : localPkgs) {
// 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;
}
}

View File

@@ -131,6 +131,7 @@ public class UpdaterWindowImpl {
mAvdManagerPage = new AvdManagerPage(mPagesRootComposite, mUpdaterData);
mLocalPackagePage = new LocalPackagesPage(mPagesRootComposite, mUpdaterData);
mRemotePackagesPage = new RemotePackagesPage(mPagesRootComposite, mUpdaterData);
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.
*/
private void firstInit() {
mUpdaterData.setWindowShell(getShell());
mTaskFactory = new ProgressTaskFactory(getShell());
mUpdaterData.setTaskFactory(mTaskFactory);
mUpdaterData.setImageFactory(new ImageFactory(getShell().getDisplay()));