am 70337978: Merge change 4208 into donut
Merge commit '70337978d53c6097577fa03967e256a020cf3253' * commit '70337978d53c6097577fa03967e256a020cf3253': SDK Updater: update all existing local archives, license click through. Modify archquery to be able to print any system property. Add downloadprovider permission tests runtest shortcut.
This commit is contained in:
committed by
The Android Open Source Project
commit
4b6a0c77ba
@@ -392,6 +392,11 @@ Native tests:
|
||||
package="com.android.providers.contactstests"
|
||||
coverage_target="ContactsProvider" />
|
||||
|
||||
<test name="downloadprovider-permission"
|
||||
build_path="packages/providers/DownloadProvider/tests/permission"
|
||||
package="com.android.providers.downloads.permission.tests"
|
||||
coverage_target="DownloadProvider" />
|
||||
|
||||
<test name="email"
|
||||
build_path="packages/apps/Email"
|
||||
package="com.android.email.tests"
|
||||
|
||||
@@ -45,6 +45,12 @@ package com.android.archquery;
|
||||
*/
|
||||
public final class Main {
|
||||
public static void main(String[] args) {
|
||||
|
||||
for (String arg : args) {
|
||||
System.out.println(String.format("%1$s: %2$s", arg, System.getProperty(arg)));
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
// Values listed from http://lopica.sourceforge.net/os.html
|
||||
String arch = System.getProperty("os.arch");
|
||||
|
||||
@@ -62,4 +68,5 @@ public final class Main {
|
||||
System.out.print(arch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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*/);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
|
||||
Reference in New Issue
Block a user