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