Home | History | Annotate | Download | only in actions
      1 /*
      2  * Copyright (C) 2009 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.actions;
     18 
     19 import com.android.ide.eclipse.adt.AdtPlugin;
     20 import com.android.ide.eclipse.adt.internal.build.DexWrapper;
     21 import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog;
     22 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
     23 import com.android.sdklib.SdkConstants;
     24 import com.android.sdklib.io.FileOp;
     25 import com.android.sdklib.util.GrabProcessOutput;
     26 import com.android.sdklib.util.GrabProcessOutput.IProcessOutput;
     27 import com.android.sdklib.util.GrabProcessOutput.Wait;
     28 import com.android.sdkuilib.repository.ISdkChangeListener;
     29 import com.android.sdkuilib.repository.SdkUpdaterWindow;
     30 import com.android.sdkuilib.repository.SdkUpdaterWindow.SdkInvocationContext;
     31 
     32 import org.eclipse.jface.action.IAction;
     33 import org.eclipse.jface.viewers.ISelection;
     34 import org.eclipse.ui.IObjectActionDelegate;
     35 import org.eclipse.ui.IWorkbenchPart;
     36 import org.eclipse.ui.IWorkbenchWindow;
     37 import org.eclipse.ui.IWorkbenchWindowActionDelegate;
     38 
     39 import java.io.File;
     40 
     41 /**
     42  * Delegate for the toolbar/menu action "Android SDK Manager".
     43  * It displays the Android SDK Manager.
     44  */
     45 public class SdkManagerAction implements IWorkbenchWindowActionDelegate, IObjectActionDelegate {
     46 
     47     @Override
     48     public void dispose() {
     49         // nothing to dispose.
     50     }
     51 
     52     @Override
     53     public void init(IWorkbenchWindow window) {
     54         // no init
     55     }
     56 
     57     @Override
     58     public void run(IAction action) {
     59         if (!openAdtSdkManager()) {
     60             AdtPlugin.displayError(
     61                     "Android SDK",
     62                     "Location of the Android SDK has not been setup in the preferences.");
     63         }
     64     }
     65 
     66     /**
     67      * Opens the SDK Manager as an external application.
     68      * This call is asynchronous, it doesn't wait for the manager to be closed.
     69      *
     70      * @return True if the application was found and executed. False if it could not
     71      *   be located or could not be launched.
     72      */
     73     public static boolean openExternalSdkManager() {
     74         final Sdk sdk = Sdk.getCurrent();
     75         if (sdk == null) {
     76             return false;
     77         }
     78 
     79         File androidBat = FileOp.append(
     80                 sdk.getSdkLocation(),
     81                 SdkConstants.FD_TOOLS,
     82                 SdkConstants.androidCmdName());
     83 
     84         if (!androidBat.exists()) {
     85             return false;
     86         }
     87 
     88         try {
     89             final AdtConsoleSdkLog logger = new AdtConsoleSdkLog();
     90 
     91             String command[] = new String[] {
     92                     androidBat.getAbsolutePath(),
     93                     "sdk"   //$NON-NLS-1$
     94             };
     95             Process process = Runtime.getRuntime().exec(command);
     96             GrabProcessOutput.grabProcessOutput(
     97                     process,
     98                     Wait.ASYNC,
     99                     new IProcessOutput() {
    100                         @Override
    101                         public void out(String line) {
    102                             // Ignore stdout
    103                         }
    104 
    105                         @Override
    106                         public void err(String line) {
    107                             if (line != null) {
    108                                 logger.printf("[SDK Manager] %s", line);
    109                             }
    110                         }
    111                     });
    112         } catch (Exception ignore) {
    113         }
    114 
    115         return true;
    116     }
    117 
    118     /**
    119      * Opens the SDK Manager bundled within ADT.
    120      * The call is blocking and does not return till the SD Manager window is closed.
    121      *
    122      * @return True if the SDK location is known and the SDK Manager was started.
    123      *   False if the SDK location is not set and we can't open a SDK Manager to
    124      *   manage files in an unknown location.
    125      */
    126     public static boolean openAdtSdkManager() {
    127         final Sdk sdk = Sdk.getCurrent();
    128         if (sdk == null) {
    129             return false;
    130         }
    131 
    132         // Runs the updater window, directing only warning/errors logs to the ADT console
    133         // (normal log is just dropped, which is fine since the SDK Manager has its own
    134         // log window now.)
    135 
    136         SdkUpdaterWindow window = new SdkUpdaterWindow(
    137                 AdtPlugin.getDisplay().getActiveShell(),
    138                 new AdtConsoleSdkLog() {
    139                     @Override
    140                     public void printf(String msgFormat, Object... args) {
    141                         // Do not show non-error/warning log in Eclipse.
    142                     };
    143                 },
    144                 sdk.getSdkLocation(),
    145                 SdkInvocationContext.IDE);
    146 
    147         ISdkChangeListener listener = new ISdkChangeListener() {
    148             @Override
    149             public void onSdkLoaded() {
    150                 // Ignore initial load of the SDK.
    151             }
    152 
    153             /**
    154              * Unload all we can from the SDK before new packages are installed.
    155              * Typically we need to get rid of references to dx from platform-tools
    156              * and to any platform resource data.
    157              * <p/>
    158              * {@inheritDoc}
    159              */
    160             @Override
    161             public void preInstallHook() {
    162 
    163                 // TODO we need to unload as much of as SDK as possible. Otherwise
    164                 // on Windows we end up with Eclipse locking some files and we can't
    165                 // replace them.
    166                 //
    167                 // At this point, we know what the user wants to install so it would be
    168                 // possible to pass in flags to know what needs to be unloaded. Typically
    169                 // we need to:
    170                 // - unload dex if platform-tools is going to be updated. There's a vague
    171                 //   attempt below at removing any references to dex and GCing. Seems
    172                 //   to do the trick.
    173                 // - unload any target that is going to be updated since it may have
    174                 //   resource data used by a current layout editor (e.g. data/*.ttf
    175                 //   and various data/res/*.xml).
    176                 //
    177                 // Most important we need to make sure there isn't a build going on
    178                 // and if there is one, either abort it or wait for it to complete and
    179                 // then we want to make sure we don't get any attempt to use the SDK
    180                 // before the postInstallHook is called.
    181 
    182                 if (sdk != null) {
    183                     sdk.unloadTargetData(true /*preventReload*/);
    184 
    185                     DexWrapper dx = sdk.getDexWrapper();
    186                     dx.unload();
    187                 }
    188             }
    189 
    190             /**
    191              * Nothing to do. We'll reparse the SDK later in onSdkReload.
    192              * <p/>
    193              * {@inheritDoc}
    194              */
    195             @Override
    196             public void postInstallHook() {
    197             }
    198 
    199             /**
    200              * Reparse the SDK in case anything was add/removed.
    201              * <p/>
    202              * {@inheritDoc}
    203              */
    204             @Override
    205             public void onSdkReload() {
    206                 AdtPlugin.getDefault().reparseSdk();
    207             }
    208         };
    209 
    210         window.addListener(listener);
    211         window.open();
    212 
    213         return true;
    214     }
    215 
    216     @Override
    217     public void selectionChanged(IAction action, ISelection selection) {
    218         // nothing related to the current selection.
    219     }
    220 
    221     @Override
    222     public void setActivePart(IAction action, IWorkbenchPart targetPart) {
    223         // nothing to do.
    224     }
    225 }
    226