• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.sdkuilib.internal.repository.sdkman2;
18 
19 
20 import com.android.sdklib.AndroidVersion;
21 import com.android.sdklib.ISdkLog;
22 import com.android.sdklib.internal.repository.packages.ExtraPackage;
23 import com.android.sdklib.internal.repository.packages.Package;
24 import com.android.sdklib.internal.repository.packages.PlatformPackage;
25 import com.android.sdklib.internal.repository.packages.PlatformToolPackage;
26 import com.android.sdklib.internal.repository.packages.ToolPackage;
27 import com.android.sdklib.internal.repository.sources.SdkSource;
28 import com.android.sdkuilib.internal.repository.SettingsController;
29 import com.android.sdkuilib.internal.repository.UpdaterData;
30 import com.android.sdkuilib.internal.repository.sdkman2.PackageLoader.IAutoInstallTask;
31 import com.android.sdkuilib.internal.tasks.ProgressView;
32 import com.android.sdkuilib.internal.tasks.ProgressViewFactory;
33 import com.android.sdkuilib.ui.GridDataBuilder;
34 import com.android.sdkuilib.ui.GridLayoutBuilder;
35 import com.android.sdkuilib.ui.SwtBaseDialog;
36 import com.android.util.Pair;
37 
38 import org.eclipse.swt.SWT;
39 import org.eclipse.swt.graphics.Point;
40 import org.eclipse.swt.layout.GridLayout;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Label;
43 import org.eclipse.swt.widgets.ProgressBar;
44 import org.eclipse.swt.widgets.Shell;
45 
46 import java.io.File;
47 import java.util.Map;
48 import java.util.Map.Entry;
49 import java.util.Set;
50 
51 /**
52  * This is a private implementation of UpdateWindow for ADT,
53  * designed to install a very specific package.
54  * <p/>
55  * Example of usage:
56  * <pre>
57  * AdtUpdateDialog dialog = new AdtUpdateDialog(
58  *     AdtPlugin.getDisplay().getActiveShell(),
59  *     new AdtConsoleSdkLog(),
60  *     sdk.getSdkLocation());
61  *
62  * Pair<Boolean, File> result = dialog.installExtraPackage(
63  *     "android", "compatibility");  //$NON-NLS-1$ //$NON-NLS-2$
64  * or
65  * Pair<Boolean, File> result = dialog.installPlatformPackage(11);
66  * </pre>
67  */
68 public class AdtUpdateDialog extends SwtBaseDialog {
69 
70     public static final int USE_MAX_REMOTE_API_LEVEL = 0;
71 
72     private static final String APP_NAME = "Android SDK Manager";
73     private final UpdaterData mUpdaterData;
74 
75     private Boolean mResultCode = Boolean.FALSE;
76     private Map<Package, File> mResultPaths = null;
77     private SettingsController mSettingsController;
78     private PackageFilter mPackageFilter;
79     private PackageLoader mPackageMananger;
80 
81     private ProgressBar mProgressBar;
82     private Label mStatusText;
83 
84     /**
85      * Creates a new {@link AdtUpdateDialog}.
86      * Callers will want to call {@link #installExtraPackage} or
87      * {@link #installPlatformPackage} after this.
88      *
89      * @param parentShell The existing parent shell. Must not be null.
90      * @param sdkLog An SDK logger. Must not be null.
91      * @param osSdkRoot The current SDK root OS path. Must not be null or empty.
92      */
AdtUpdateDialog( Shell parentShell, ISdkLog sdkLog, String osSdkRoot)93     public AdtUpdateDialog(
94             Shell parentShell,
95             ISdkLog sdkLog,
96             String osSdkRoot) {
97         super(parentShell, SWT.NONE, APP_NAME);
98         mUpdaterData = new UpdaterData(osSdkRoot, sdkLog);
99     }
100 
101     /**
102      * Displays the update dialog and triggers installation of the requested {@code extra}
103      * package with the specified vendor and path attributes.
104      * <p/>
105      * Callers must not try to reuse this dialog after this call.
106      *
107      * @param vendor The extra package vendor string to match.
108      * @param path   The extra package path   string to match.
109      * @return A boolean indicating whether the installation was successful (meaning the package
110      *   was either already present, or got installed or updated properly) and a {@link File}
111      *   with the path to the root folder of the package. The file is null when the boolean
112      *   is false, otherwise it should point to an existing valid folder.
113      * @wbp.parser.entryPoint
114      */
installExtraPackage(String vendor, String path)115     public Pair<Boolean, File> installExtraPackage(String vendor, String path) {
116         mPackageFilter = createExtraFilter(vendor, path);
117         open();
118 
119         File installPath = null;
120         if (mResultPaths != null) {
121             for (Entry<Package, File> entry : mResultPaths.entrySet()) {
122                 if (entry.getKey() instanceof ExtraPackage) {
123                     installPath = entry.getValue();
124                     break;
125                 }
126             }
127         }
128 
129         return Pair.of(mResultCode, installPath);
130     }
131 
132     /**
133      * Displays the update dialog and triggers installation of the requested platform
134      * package with the specified API  level.
135      * <p/>
136      * Callers must not try to reuse this dialog after this call.
137      *
138      * @param apiLevel The platform API level to match.
139      *  The special value {@link #USE_MAX_REMOTE_API_LEVEL} means to use
140      *  the highest API level available on the remote repository.
141      * @return A boolean indicating whether the installation was successful (meaning the package
142      *   was either already present, or got installed or updated properly) and a {@link File}
143      *   with the path to the root folder of the package. The file is null when the boolean
144      *   is false, otherwise it should point to an existing valid folder.
145      */
installPlatformPackage(int apiLevel)146     public Pair<Boolean, File> installPlatformPackage(int apiLevel) {
147         mPackageFilter = createPlatformFilter(apiLevel);
148         open();
149 
150         File installPath = null;
151         if (mResultPaths != null) {
152             for (Entry<Package, File> entry : mResultPaths.entrySet()) {
153                 if (entry.getKey() instanceof PlatformPackage) {
154                     installPath = entry.getValue();
155                     break;
156                 }
157             }
158         }
159 
160         return Pair.of(mResultCode, installPath);
161     }
162 
163     /**
164      * Displays the update dialog and triggers installation of a new SDK. This works by
165      * requesting a remote platform package with the specified API levels as well as
166      * the first tools or platform-tools packages available.
167      * <p/>
168      * Callers must not try to reuse this dialog after this call.
169      *
170      * @param apiLevels A set of platform API levels to match.
171      *  The special value {@link #USE_MAX_REMOTE_API_LEVEL} means to use
172      *  the highest API level available in the repository.
173      * @return A boolean indicating whether the installation was successful (meaning the packages
174      *   were either already present, or got installed or updated properly).
175      */
installNewSdk(Set<Integer> apiLevels)176     public boolean installNewSdk(Set<Integer> apiLevels) {
177         mPackageFilter = createNewSdkFilter(apiLevels);
178         open();
179         return mResultCode.booleanValue();
180     }
181 
182     @Override
createContents()183     protected void createContents() {
184         Shell shell = getShell();
185         shell.setMinimumSize(new Point(450, 100));
186         shell.setSize(450, 100);
187 
188         mUpdaterData.setWindowShell(shell);
189 
190         GridLayoutBuilder.create(shell).columns(1);
191 
192         Composite composite1 = new Composite(shell, SWT.NONE);
193         composite1.setLayout(new GridLayout(1, false));
194         GridDataBuilder.create(composite1).fill().grab();
195 
196         mProgressBar = new ProgressBar(composite1, SWT.NONE);
197         GridDataBuilder.create(mProgressBar).hFill().hGrab();
198 
199         mStatusText = new Label(composite1, SWT.NONE);
200         mStatusText.setText("Status Placeholder");  //$NON-NLS-1$ placeholder
201         GridDataBuilder.create(mStatusText).hFill().hGrab();
202     }
203 
204     @Override
postCreate()205     protected void postCreate() {
206         ProgressViewFactory factory = new ProgressViewFactory();
207         factory.setProgressView(new ProgressView(
208                 mStatusText,
209                 mProgressBar,
210                 null /*buttonStop*/,
211                 new SdkLogAdapter(mUpdaterData.getSdkLog())));
212         mUpdaterData.setTaskFactory(factory);
213 
214         setupSources();
215         initializeSettings();
216 
217         if (mUpdaterData.checkIfInitFailed()) {
218             close();
219             return;
220         }
221 
222         mUpdaterData.broadcastOnSdkLoaded();
223 
224         mPackageMananger = new PackageLoader(mUpdaterData);
225     }
226 
227     @Override
eventLoop()228     protected void eventLoop() {
229         mPackageMananger.loadPackagesWithInstallTask(
230                 mPackageFilter.installFlags(),
231                 new IAutoInstallTask() {
232             @Override
233             public Package[] filterLoadedSource(SdkSource source, Package[] packages) {
234                 for (Package pkg : packages) {
235                     mPackageFilter.visit(pkg);
236                 }
237                 return packages;
238             }
239 
240             @Override
241             public boolean acceptPackage(Package pkg) {
242                 // Is this the package we want to install?
243                 return mPackageFilter.accept(pkg);
244             }
245 
246             @Override
247             public void setResult(boolean success, Map<Package, File> installPaths) {
248                 // Capture the result from the installation.
249                 mResultCode = Boolean.valueOf(success);
250                 mResultPaths = installPaths;
251             }
252 
253             @Override
254             public void taskCompleted() {
255                 // We can close that window now.
256                 close();
257             }
258         });
259 
260         super.eventLoop();
261     }
262 
263     // -- Start of internal part ----------
264     // Hide everything down-below from SWT designer
265     //$hide>>$
266 
267     // --- Public API -----------
268 
269 
270     // --- Internals & UI Callbacks -----------
271 
272     /**
273      * Used to initialize the sources.
274      */
setupSources()275     private void setupSources() {
276         mUpdaterData.setupDefaultSources();
277     }
278 
279     /**
280      * Initializes settings.
281      */
initializeSettings()282     private void initializeSettings() {
283         mSettingsController = mUpdaterData.getSettingsController();
284         mSettingsController.loadSettings();
285         mSettingsController.applySettings();
286     }
287 
288     // ----
289 
290     private static abstract class PackageFilter {
291         /** Returns the installer flags for the corresponding mode. */
installFlags()292         abstract int installFlags();
293 
294         /** Visit a new package definition, in case we need to adjust the filter dynamically. */
visit(Package pkg)295         abstract void visit(Package pkg);
296 
297         /** Checks whether this is the package we've been looking for. */
accept(Package pkg)298         abstract boolean accept(Package pkg);
299     }
300 
createExtraFilter( final String vendor, final String path)301     public static PackageFilter createExtraFilter(
302             final String vendor,
303             final String path) {
304         return new PackageFilter() {
305             String mVendor = vendor;
306             String mPath = path;
307 
308             @Override
309             boolean accept(Package pkg) {
310                 if (pkg instanceof ExtraPackage) {
311                     ExtraPackage ep = (ExtraPackage) pkg;
312                     if (ep.getVendorId().equals(mVendor)) {
313                         // Check actual extra <path> field first
314                         if (ep.getPath().equals(mPath)) {
315                             return true;
316                         }
317                         // If not, check whether this is one of the <old-paths> values.
318                         for (String oldPath : ep.getOldPaths()) {
319                             if (oldPath.equals(mPath)) {
320                                 return true;
321                             }
322                         }
323                     }
324                 }
325                 return false;
326             }
327 
328             @Override
329             void visit(Package pkg) {
330                 // nop
331             }
332 
333             @Override
334             int installFlags() {
335                 return UpdaterData.TOOLS_MSG_UPDATED_FROM_ADT;
336             }
337         };
338     }
339 
createPlatformFilter(final int apiLevel)340     public static PackageFilter createPlatformFilter(final int apiLevel) {
341         return new PackageFilter() {
342             int mApiLevel = apiLevel;
343             boolean mFindMaxApi = apiLevel == USE_MAX_REMOTE_API_LEVEL;
344 
345             @Override
346             boolean accept(Package pkg) {
347                 if (pkg instanceof PlatformPackage) {
348                     PlatformPackage pp = (PlatformPackage) pkg;
349                     AndroidVersion v = pp.getVersion();
350                     return !v.isPreview() && v.getApiLevel() == mApiLevel;
351                 }
352                 return false;
353             }
354 
355             @Override
356             void visit(Package pkg) {
357                 // Try to find the max API in all remote packages
358                 if (mFindMaxApi &&
359                         pkg instanceof PlatformPackage &&
360                         !pkg.isLocal()) {
361                     PlatformPackage pp = (PlatformPackage) pkg;
362                     AndroidVersion v = pp.getVersion();
363                     if (!v.isPreview()) {
364                         int api = v.getApiLevel();
365                         if (api > mApiLevel) {
366                             mApiLevel = api;
367                         }
368                     }
369                 }
370             }
371 
372             @Override
373             int installFlags() {
374                 return UpdaterData.TOOLS_MSG_UPDATED_FROM_ADT;
375             }
376         };
377     }
378 
379     public static PackageFilter createNewSdkFilter(final Set<Integer> apiLevels) {
380         return new PackageFilter() {
381             int mMaxApiLevel;
382             boolean mFindMaxApi = apiLevels.contains(USE_MAX_REMOTE_API_LEVEL);
383             boolean mNeedTools = true;
384             boolean mNeedPlatformTools = true;
385 
386             @Override
387             boolean accept(Package pkg) {
388                 if (!pkg.isLocal()) {
389                     if (pkg instanceof PlatformPackage) {
390                         PlatformPackage pp = (PlatformPackage) pkg;
391                         AndroidVersion v = pp.getVersion();
392                         if (!v.isPreview()) {
393                             int level = v.getApiLevel();
394                             if ((mFindMaxApi && level == mMaxApiLevel) ||
395                                     (level > 0 && apiLevels.contains(level))) {
396                                 return true;
397                             }
398                         }
399                     } else if (mNeedTools && pkg instanceof ToolPackage) {
400                         // We want a tool package. There should be only one,
401                         // but in case of error just take the first one.
402                         mNeedTools = false;
403                         return true;
404                     } else if (mNeedPlatformTools && pkg instanceof PlatformToolPackage) {
405                         // We want a platform-tool package. There should be only one,
406                         // but in case of error just take the first one.
407                         mNeedPlatformTools = false;
408                         return true;
409                     }
410                 }
411                 return false;
412             }
413 
414             @Override
415             void visit(Package pkg) {
416                 // Try to find the max API in all remote packages
417                 if (mFindMaxApi &&
418                         pkg instanceof PlatformPackage &&
419                         !pkg.isLocal()) {
420                     PlatformPackage pp = (PlatformPackage) pkg;
421                     AndroidVersion v = pp.getVersion();
422                     if (!v.isPreview()) {
423                         int api = v.getApiLevel();
424                         if (api > mMaxApiLevel) {
425                             mMaxApiLevel = api;
426                         }
427                     }
428                 }
429             }
430 
431             @Override
432             int installFlags() {
433                 return UpdaterData.NO_TOOLS_MSG;
434             }
435         };
436     }
437 
438 
439 
440     // End of hiding from SWT Designer
441     //$hide<<$
442 
443     // -----
444 
445 }
446