Home | History | Annotate | Download | only in welcome
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
      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.ide.eclipse.adt.internal.welcome;
     18 
     19 import com.android.ide.eclipse.adt.AdtPlugin;
     20 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
     21 import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog;
     22 import com.android.sdkstats.DdmsPreferenceStore;
     23 import com.android.sdkuilib.internal.repository.ui.AdtUpdateDialog;
     24 
     25 import org.eclipse.core.runtime.IStatus;
     26 import org.eclipse.jface.resource.ImageDescriptor;
     27 import org.eclipse.jface.wizard.Wizard;
     28 import org.eclipse.swt.widgets.Display;
     29 import org.eclipse.swt.widgets.Shell;
     30 import org.eclipse.ui.IWorkbench;
     31 import org.eclipse.ui.IWorkbenchWindow;
     32 import org.eclipse.ui.PlatformUI;
     33 
     34 import java.io.File;
     35 import java.util.HashSet;
     36 import java.util.Set;
     37 
     38 /**
     39  * Wizard shown on first start for new users: configure SDK location, accept or
     40  * reject usage data collection, etc
     41  */
     42 public class WelcomeWizard extends Wizard {
     43     private final DdmsPreferenceStore mStore;
     44 
     45     private WelcomeWizardPage mWelcomePage;
     46     private UsagePermissionPage mUsagePage;
     47 
     48     private final boolean mShowWelcomePage;
     49     private final boolean mShowUsagePage;
     50 
     51     /**
     52      * Creates a new {@link WelcomeWizard}
     53      *
     54      * @param store preferences for usage statistics collection etc
     55      * @param showInstallSdkPage show page to install SDK's
     56      * @param showUsageOptinPage show page to get user consent for usage data collection
     57      */
     58     public WelcomeWizard(DdmsPreferenceStore store, boolean showInstallSdkPage,
     59             boolean showUsageOptinPage) {
     60         mStore = store;
     61         mShowWelcomePage = showInstallSdkPage;
     62         mShowUsagePage = showUsageOptinPage;
     63 
     64         setWindowTitle("Welcome to Android Development");
     65         ImageDescriptor image = AdtPlugin.getImageDescriptor("icons/android-64.png"); //$NON-NLS-1$
     66         setDefaultPageImageDescriptor(image);
     67     }
     68 
     69     @Override
     70     public void addPages() {
     71         if (mShowWelcomePage) {
     72             mWelcomePage = new WelcomeWizardPage();
     73             addPage(mWelcomePage);
     74         }
     75 
     76         // It's possible that the user has already run the command line tools
     77         // such as ddms and has agreed to usage statistics collection, but has never
     78         // run ADT which is why the wizard was opened. No need to ask again.
     79         if (mShowUsagePage && !mStore.hasPingId()) {
     80             mUsagePage = new UsagePermissionPage();
     81             addPage(mUsagePage);
     82         }
     83     }
     84 
     85     @Override
     86     public boolean performFinish() {
     87         if (mUsagePage != null) {
     88             boolean isUsageCollectionApproved = mUsagePage.isUsageCollectionApproved();
     89             DdmsPreferenceStore store = new DdmsPreferenceStore();
     90 
     91             // Workaround: Store a new ping id if one doesn't exist, regardless of
     92             // whether usage statistics gathering is enabled, to ensure that ddms and
     93             // ADT agree upon whether usage data collection is enabled. The reason this
     94             // is necessary is that the Eclipse PreferenceStore optimizes out writing
     95             // property values that equal their default values, and in our case, the
     96             // default value for usage-collection is "false", so it just doesn't write
     97             // it into the config file is the user opts out - which means that nothing
     98             // is written in ddms.config. That works in the sense that the getter returns
     99             // "usage collection"=false, but it doesn't work in the sense that it looks
    100             // like the property has not yet been decided by the user. DDMS will look at
    101             // the existence of a ping id to see whether we've already considered the
    102             // question, so do the same here.
    103             if (!store.hasPingId()) {
    104                 store.generateNewPingId();
    105             }
    106 
    107             store.setPingOptIn(isUsageCollectionApproved);
    108         }
    109 
    110         if (mWelcomePage != null) {
    111             // Read out wizard settings immediately; we will perform the actual work
    112             // after the wizard window has been taken down and it's too late to read the
    113             // settings then
    114             final File path = mWelcomePage.getPath();
    115             final boolean installCommon = mWelcomePage.isInstallCommon();
    116             final boolean installLatest = mWelcomePage.isInstallLatest();
    117             final boolean createNew = mWelcomePage.isCreateNew();
    118 
    119             // Perform installation asynchronously since it takes a while.
    120             getShell().getDisplay().asyncExec(new Runnable() {
    121                 @Override
    122                 public void run() {
    123                     if (createNew) {
    124                         try {
    125                             Set<Integer> apiLevels = new HashSet<Integer>();
    126                             if (installCommon) {
    127                                 apiLevels.add(8);
    128                             }
    129                             if (installLatest) {
    130                                 apiLevels.add(AdtUpdateDialog.USE_MAX_REMOTE_API_LEVEL);
    131                             }
    132                             installSdk(path, apiLevels);
    133                         } catch (Exception e) {
    134                             AdtPlugin.logAndPrintError(e, "ADT Welcome Wizard",
    135                                     "Installation failed");
    136                         }
    137                     }
    138 
    139                     // Set SDK path after installation since this will trigger a SDK refresh.
    140                     AdtPrefs.getPrefs().setSdkLocation(path);
    141                 }
    142             });
    143         }
    144 
    145         // The wizard always succeeds, even if installation fails or is aborted
    146         return true;
    147     }
    148 
    149     /**
    150      * Trigger the install window. It will connect to the repository, display
    151      * a confirmation window showing which packages are selected for install
    152      * and display a progress dialog during installation.
    153      */
    154     private boolean installSdk(File path, Set<Integer> apiLevels) {
    155         if (!path.isDirectory()) {
    156             if (!path.mkdirs()) {
    157                 AdtPlugin.logAndPrintError(null, "ADT Welcome Wizard",
    158                         "Failed to create directory %1$s",
    159                         path.getAbsolutePath());
    160                 return false;
    161             }
    162         }
    163 
    164         // Get a shell to use for the SDK installation. There are cases where getActiveShell
    165         // returns null so attempt to obtain it through other means.
    166         Display display = AdtPlugin.getDisplay();
    167         Shell shell = display.getActiveShell();
    168         if (shell == null) {
    169             IWorkbench workbench = PlatformUI.getWorkbench();
    170             IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
    171             if (window != null) {
    172                 shell = window.getShell();
    173             }
    174         }
    175         boolean disposeShell = false;
    176         if (shell == null) {
    177             shell = new Shell(display);
    178             AdtPlugin.log(IStatus.WARNING, "No parent shell for SDK installation dialog");
    179             disposeShell = true;
    180         }
    181 
    182         AdtUpdateDialog updater = new AdtUpdateDialog(
    183                 shell,
    184                 new AdtConsoleSdkLog(),
    185                 path.getAbsolutePath());
    186         // Note: we don't have to specify tools & platform-tools since they
    187         // are required dependencies of any platform.
    188         boolean result = updater.installNewSdk(apiLevels);
    189 
    190         // TODO: Install extra package here as well since it is now core to most of
    191         // the templates
    192         // if (result) {
    193         //     updater.installExtraPackage(vendor, path);
    194         // }
    195 
    196         if (disposeShell) {
    197             shell.dispose();
    198         }
    199 
    200         if (!result) {
    201             AdtPlugin.printErrorToConsole("Failed to install Android SDK.");
    202             return false;
    203         }
    204 
    205         return true;
    206     }
    207 }
    208