diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java b/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java index ac7c4e4cb..8ab1364c8 100755 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java @@ -19,6 +19,8 @@ package com.android.sdkmanager.internal.repository; import com.android.sdkuilib.internal.repository.ISettingsPage; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; @@ -39,13 +41,20 @@ public class SettingsPage extends Composite implements ISettingsPage { // UI widgets private Group mProxySettingsGroup; - private Group mPlaceholderGroup; + private Group mMiscGroup; private Button mApplyButton; - private Label mSomeMoreSettings; private Label mProxyServerLabel; private Label mProxyPortLabel; private Text mProxyServerText; private Text mProxyPortText; + private Button mForceHttpCheck; + + private ModifyListener mSetApplyDirty = new ModifyListener() { + public void modifyText(ModifyEvent e) { + mApplyButton.setEnabled(true); + } + }; + /** * Create the composite. @@ -67,6 +76,7 @@ public class SettingsPage extends Composite implements ISettingsPage { mProxyServerText = new Text(mProxySettingsGroup, SWT.BORDER); mProxyServerText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + mProxyServerText.addModifyListener(mSetApplyDirty); mProxyPortLabel = new Label(mProxySettingsGroup, SWT.NONE); mProxyPortLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); @@ -74,24 +84,31 @@ public class SettingsPage extends Composite implements ISettingsPage { mProxyPortText = new Text(mProxySettingsGroup, SWT.BORDER); mProxyPortText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + mProxyPortText.addModifyListener(mSetApplyDirty); - mPlaceholderGroup = new Group(this, SWT.NONE); - mPlaceholderGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); - mPlaceholderGroup.setText("Placeholder"); - mPlaceholderGroup.setLayout(new GridLayout(1, false)); + mMiscGroup = new Group(this, SWT.NONE); + mMiscGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); + mMiscGroup.setText("Misc"); + mMiscGroup.setLayout(new GridLayout(2, false)); - mSomeMoreSettings = new Label(mPlaceholderGroup, SWT.NONE); - mSomeMoreSettings.setText("Some more settings here"); + mForceHttpCheck = new Button(mMiscGroup, SWT.CHECK); + mForceHttpCheck.setText("Force https://... sources to be fetched using http://..."); + mForceHttpCheck.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onForceHttpSelected(); //$hide$ + } + }); mApplyButton = new Button(this, SWT.NONE); + mApplyButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + mApplyButton.setText("Save && Apply"); mApplyButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { onApplySelected(); //$hide$ } }); - mApplyButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - mApplyButton.setText("Save && Apply"); postCreate(); //$hide$ } @@ -105,6 +122,8 @@ public class SettingsPage extends Composite implements ISettingsPage { // Disable the check that prevents subclassing of SWT components } + + // -- Start of internal part ---------- // Hide everything down-below from SWT designer //$hide>>$ @@ -117,15 +136,21 @@ public class SettingsPage extends Composite implements ISettingsPage { /** Loads settings from the given {@link Properties} container and update the page UI. */ public void loadSettings(Properties in_settings) { - mProxyServerText.setText(in_settings.getProperty(JAVA_HTTP_PROXY_HOST, "")); //$NON-NLS-1$ - mProxyPortText.setText(in_settings.getProperty(JAVA_HTTP_PROXY_PORT, "")); //$NON-NLS-1$ + mProxyServerText.setText(in_settings.getProperty(KEY_HTTP_PROXY_HOST, "")); //$NON-NLS-1$ + mProxyPortText.setText( in_settings.getProperty(KEY_HTTP_PROXY_PORT, "")); //$NON-NLS-1$ + mForceHttpCheck.setSelection(Boolean.parseBoolean(in_settings.getProperty(KEY_FORCE_HTTP))); + + // We loaded fresh settings so there's nothing dirty to apply + mApplyButton.setEnabled(false); } /** Called by the application to retrieve settings from the UI and store them in * the given {@link Properties} container. */ public void retrieveSettings(Properties out_settings) { - out_settings.put(JAVA_HTTP_PROXY_HOST, mProxyServerText.getText()); - out_settings.put(JAVA_HTTP_PROXY_PORT, mProxyPortText.getText()); + out_settings.setProperty(KEY_HTTP_PROXY_HOST, mProxyServerText.getText()); + out_settings.setProperty(KEY_HTTP_PROXY_PORT, mProxyPortText.getText()); + out_settings.setProperty(KEY_FORCE_HTTP, + Boolean.toString(mForceHttpCheck.getSelection())); } /** @@ -138,14 +163,23 @@ public class SettingsPage extends Composite implements ISettingsPage { } /** + * Callback invoked when user presses the "Save and Apply" button. * Notify the application that settings have changed. */ private void onApplySelected() { if (mSettingsChangedCallback != null) { mSettingsChangedCallback.onSettingsChanged(this); + mApplyButton.setEnabled(false); } } + /** + * Callback invoked when the users presses the Force HTTPS checkbox. + */ + private void onForceHttpSelected() { + mSetApplyDirty.modifyText(null); + } + // End of hiding from SWT Designer //$hide<<$ } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java index ab58adf2d..08a536b51 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java @@ -341,7 +341,7 @@ public class Archive implements IDescription { * * @return True if the archive was installed, false otherwise. */ - public boolean install(String osSdkRoot, ITaskMonitor monitor) { + public boolean install(String osSdkRoot, boolean forceHttp, ITaskMonitor monitor) { File archiveFile = null; try { @@ -362,7 +362,7 @@ public class Archive implements IDescription { return false; } - archiveFile = downloadFile(monitor); + archiveFile = downloadFile(monitor, forceHttp); if (archiveFile != null) { if (unarchive(osSdkRoot, archiveFile, monitor)) { monitor.setResult("Installed: %1$s", name); @@ -382,7 +382,7 @@ public class Archive implements IDescription { * Downloads an archive and returns the temp file with it. * Caller is responsible with deleting the temp file when done. */ - private File downloadFile(ITaskMonitor monitor) { + private File downloadFile(ITaskMonitor monitor, boolean forceHttp) { File tmpFileToDelete = null; try { @@ -414,6 +414,10 @@ public class Archive implements IDescription { link = base + link; } + if (forceHttp) { + link = link.replaceAll("https://", "http://"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (fetchUrl(tmpFile, link, desc, monitor)) { // Fetching was successful, don't delete the temp file here! tmpFileToDelete = null; diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java index c58a21412..258ecbc6f 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java @@ -68,7 +68,7 @@ public class RepoSource implements IDescription { } /** - * Returns the list of known packages found by the last call to {@link #load(ITaskMonitor)}. + * Returns the list of known packages found by the last call to load(). * This is null when the source hasn't been loaded yet. */ public Package[] getPackages() { @@ -77,7 +77,7 @@ public class RepoSource implements IDescription { /** * Clear the internal packages list. After this call, {@link #getPackages()} will return - * null till {@link #load(ITaskMonitor)} is called. + * null till load() is called. */ public void clearPackages() { mPackages = null; @@ -94,19 +94,24 @@ public class RepoSource implements IDescription { /** * Tries to fetch the repository index for the given URL. */ - public void load(ITaskMonitor monitor) { + public void load(ITaskMonitor monitor, boolean forceHttp) { monitor.setProgressMax(4); setDefaultDescription(); - monitor.setDescription("Fetching %1$s", mUrl); + String url = mUrl; + if (forceHttp) { + url = url.replaceAll("https://", "http://"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + monitor.setDescription("Fetching %1$s", url); monitor.incProgress(1); - String xml = fetchUrl(mUrl, monitor); + String xml = fetchUrl(url, monitor); if (xml == null) { - mDescription += String.format("\nFailed to fetch URL %1$s", mUrl); + mDescription += String.format("\nFailed to fetch URL %1$s", url); return; } @@ -114,7 +119,7 @@ public class RepoSource implements IDescription { monitor.incProgress(1); if (!validateXml(xml, monitor)) { - mDescription += String.format("\nFailed to validate XML at %1$s", mUrl); + mDescription += String.format("\nFailed to validate XML at %1$s", url); return; } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java index 0a70953ed..2e126e946 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java @@ -24,19 +24,10 @@ import java.util.ArrayList; public class RepoSources { private ArrayList mSources = new ArrayList(); - private ITaskFactory mTaskFactory; public RepoSources() { } - public void setTaskFactory(ITaskFactory taskFactory) { - mTaskFactory = taskFactory; - } - - public ITaskFactory getTaskFactory() { - return mTaskFactory; - } - public void add(RepoSource source) { mSources.add(source); } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ISettingsPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ISettingsPage.java index 02d0b6ee3..3930bf1aa 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ISettingsPage.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ISettingsPage.java @@ -24,10 +24,12 @@ import java.util.Properties; */ public interface ISettingsPage { - /** Java system setting picked up by {@link URL} for http proxy port */ - public static final String JAVA_HTTP_PROXY_PORT = "http.proxyPort"; //$NON-NLS-1$ - /** Java system setting picked up by {@link URL} for http proxy host */ - public static final String JAVA_HTTP_PROXY_HOST = "http.proxyHost"; //$NON-NLS-1$ + /** Java system setting picked up by {@link URL} for http proxy port. Type: String. */ + public static final String KEY_HTTP_PROXY_PORT = "http.proxyPort"; //$NON-NLS-1$ + /** Java system setting picked up by {@link URL} for http proxy host. Type: String. */ + public static final String KEY_HTTP_PROXY_HOST = "http.proxyHost"; //$NON-NLS-1$ + /** Setting to force using http:// instead of https:// connections. Type: Boolean. */ + public static final String KEY_FORCE_HTTP = "sdkman.force.http"; //$NON-NLS-1$ /** Loads settings from the given {@link Properties} container and update the page UI. */ public abstract void loadSettings(Properties in_settings); diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java index 4f8668014..fa530fa4f 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java @@ -25,7 +25,6 @@ import com.android.sdklib.internal.repository.ITaskMonitor; import com.android.sdklib.internal.repository.Package; import com.android.sdklib.internal.repository.PlatformPackage; import com.android.sdklib.internal.repository.RepoSource; -import com.android.sdklib.internal.repository.RepoSources; import com.android.sdklib.internal.repository.ToolPackage; import com.android.sdkuilib.internal.repository.icons.ImageFactory; @@ -43,18 +42,10 @@ import org.eclipse.swt.graphics.Image; */ class RepoSourcesAdapter { - private final RepoSources mRepoSources; - private ImageFactory mImageFactory; + private final UpdaterData mUpdaterData; - public RepoSourcesAdapter(RepoSources repoSources) { - mRepoSources = repoSources; - } - - /** - * Set the image factory used by the label provider. - */ - public void setImageFactory(ImageFactory imageFactory) { - mImageFactory = imageFactory; + public RepoSourcesAdapter(UpdaterData updaterData) { + mUpdaterData = updaterData; } public ILabelProvider getLabelProvider() { @@ -74,30 +65,32 @@ class RepoSourcesAdapter { @Override public Image getImage(Object element) { - if (mImageFactory != null) { + ImageFactory imgFactory = mUpdaterData.getImageFactory(); + + if (imgFactory != null) { if (element instanceof RepoSource) { - return mImageFactory.getImage("source_icon16.png"); + return imgFactory.getImage("source_icon16.png"); } else if (element instanceof PlatformPackage) { - return mImageFactory.getImage("red_ball_icon16.png"); + return imgFactory.getImage("red_ball_icon16.png"); } else if (element instanceof AddonPackage) { - return mImageFactory.getImage("green_ball_icon16.png"); + return imgFactory.getImage("green_ball_icon16.png"); } else if (element instanceof ToolPackage) { - return mImageFactory.getImage("blue_ball_icon16.png"); + return imgFactory.getImage("blue_ball_icon16.png"); } else if (element instanceof DocPackage) { - return mImageFactory.getImage("purple_ball_icon16.png"); + return imgFactory.getImage("purple_ball_icon16.png"); } else if (element instanceof Package) { - return mImageFactory.getImage("gray_ball_icon16.png"); + return imgFactory.getImage("gray_ball_icon16.png"); } else if (element instanceof Archive) { if (((Archive) element).isCompatible()) { - return mImageFactory.getImage("archive_icon16.png"); + return imgFactory.getImage("archive_icon16.png"); } else { - return mImageFactory.getImage("incompat_icon16.png"); + return imgFactory.getImage("incompat_icon16.png"); } } } @@ -117,9 +110,7 @@ class RepoSourcesAdapter { // ------------ - private static class TreeContentProvider implements ITreeContentProvider { - - private RepoSourcesAdapter mInput; + private class TreeContentProvider implements ITreeContentProvider { // Called when the viewer is disposed public void dispose() { @@ -128,9 +119,7 @@ class RepoSourcesAdapter { // Called when the input is set or changed on the provider public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - assert newInput == null || newInput instanceof RepoSourcesAdapter; - mInput = (RepoSourcesAdapter) newInput; - // pass + assert newInput == RepoSourcesAdapter.this; } /** @@ -151,8 +140,8 @@ class RepoSourcesAdapter { * For a {@link Package}, returns an array of {@link Archive}s. */ public Object[] getChildren(Object parentElement) { - if (parentElement instanceof RepoSourcesAdapter) { - return ((RepoSourcesAdapter) parentElement).mRepoSources.getSources().toArray(); + if (parentElement == RepoSourcesAdapter.this) { + return mUpdaterData.getSources().getSources().toArray(); } else if (parentElement instanceof RepoSource) { final RepoSource source = (RepoSource) parentElement; @@ -160,9 +149,11 @@ class RepoSourcesAdapter { if (packages == null) { - mInput.mRepoSources.getTaskFactory().start("Loading Source", new ITask() { + final boolean forceHttp = mUpdaterData.getSettingsController().getForceHttp(); + + mUpdaterData.getTaskFactory().start("Loading Source", new ITask() { public void run(ITaskMonitor monitor) { - source.load(monitor); + source.load(monitor, forceHttp); } }); @@ -186,7 +177,7 @@ class RepoSourcesAdapter { public Object getParent(Object element) { if (element instanceof RepoSource) { - return mInput; + return RepoSourcesAdapter.this; } else if (element instanceof Package) { return ((Package) element).getParentSource(); diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SettingsController.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SettingsController.java index 06a69d12b..086e547b7 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SettingsController.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SettingsController.java @@ -39,6 +39,14 @@ public class SettingsController { public SettingsController() { } + //--- Access to settings ------------ + + public boolean getForceHttp() { + return Boolean.parseBoolean(mProperties.getProperty(ISettingsPage.KEY_FORCE_HTTP)); + } + + //--- Controller methods ------------- + /** * Associate the given {@link ISettingsPage} with this {@link SettingsController}. * @@ -133,10 +141,10 @@ public class SettingsController { */ public void applySettings() { Properties props = System.getProperties(); - props.put(ISettingsPage.JAVA_HTTP_PROXY_HOST, - mProperties.getProperty(ISettingsPage.JAVA_HTTP_PROXY_HOST, "")); //$NON-NLS-1$ - props.put(ISettingsPage.JAVA_HTTP_PROXY_PORT, - mProperties.getProperty(ISettingsPage.JAVA_HTTP_PROXY_PORT, "")); //$NON-NLS-1$ + props.setProperty(ISettingsPage.KEY_HTTP_PROXY_HOST, + mProperties.getProperty(ISettingsPage.KEY_HTTP_PROXY_HOST, "")); //$NON-NLS-1$ + props.setProperty(ISettingsPage.KEY_HTTP_PROXY_PORT, + mProperties.getProperty(ISettingsPage.KEY_HTTP_PROXY_PORT, "")); //$NON-NLS-1$ } } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java index 0342e6e41..ad38a82c1 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java @@ -51,7 +51,7 @@ class UpdaterData { private final RepoSources mSources = new RepoSources(); private final LocalSdkAdapter mLocalSdkAdapter = new LocalSdkAdapter(this); - private final RepoSourcesAdapter mSourcesAdapter = new RepoSourcesAdapter(mSources); + private final RepoSourcesAdapter mSourcesAdapter = new RepoSourcesAdapter(this); private ImageFactory mImageFactory; @@ -85,6 +85,10 @@ class UpdaterData { mTaskFactory = taskFactory; } + public ITaskFactory getTaskFactory() { + return mTaskFactory; + } + public void setUserCanChangeSdkRoot(boolean userCanChangeSdkRoot) { mUserCanChangeSdkRoot = userCanChangeSdkRoot; } @@ -115,7 +119,6 @@ class UpdaterData { public void setImageFactory(ImageFactory imageFactory) { mImageFactory = imageFactory; - mSourcesAdapter.setImageFactory(imageFactory); } public ImageFactory getImageFactory() { @@ -216,6 +219,8 @@ class UpdaterData { throw new IllegalArgumentException("Task Factory is null"); } + final boolean forceHttp = getSettingsController().getForceHttp(); + // TODO filter the archive list to: a/ display a list of what is going to be installed, // b/ display licenses and c/ check that the selected packages are actually upgrades // or ask user to confirm downgrades. All this should be done in a separate class+window @@ -237,7 +242,7 @@ class UpdaterData { break; } - if (archive.install(mOsSdkRoot, monitor)) { + if (archive.install(mOsSdkRoot, forceHttp, monitor)) { numInstalled++; } @@ -299,13 +304,15 @@ class UpdaterData { public void refreshSources(final boolean forceFetching, ITaskMonitor monitor) { assert mTaskFactory != null; + final boolean forceHttp = getSettingsController().getForceHttp(); + ITask task = new ITask() { public void run(ITaskMonitor monitor) { ArrayList sources = mSources.getSources(); monitor.setProgressMax(sources.size()); for (RepoSource source : sources) { if (forceFetching || source.getPackages() != null) { - source.load(monitor.createSubMonitor(1)); + source.load(monitor.createSubMonitor(1), forceHttp); } monitor.incProgress(1); diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java index 2c3d75c6b..0d1ead005 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java @@ -302,8 +302,6 @@ public class UpdaterWindowImpl { * Used to initialize the sources. */ private void setupSources() { - mUpdaterData.getSources().setTaskFactory(mTaskFactory); - mUpdaterData.getSources().add( new RepoSource(SdkRepository.URL_GOOGLE_SDK_REPO_SITE, false /* addonOnly */)); @@ -315,7 +313,6 @@ public class UpdaterWindowImpl { } } - mRemotePackagesPage.onSdkChange(); }