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.project; 18 19 import com.android.ddmlib.AndroidDebugBridge; 20 import com.android.ddmlib.IDevice; 21 import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener; 22 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; 23 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor; 24 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor.IProjectListener; 25 26 import org.eclipse.core.resources.IProject; 27 28 import java.util.ArrayList; 29 30 /** 31 * Registers which apk was installed on which device. 32 * <p/> 33 * The goal of this class is to remember the installation of APKs on devices, and provide 34 * information about whether a new APK should be installed on a device prior to running the 35 * application from a launch configuration. 36 * <p/> 37 * The manager uses {@link IProject} and {@link IDevice} to identify the target device and the 38 * (project generating the) APK. This ensures that disconnected and reconnected devices will 39 * always receive new APKs (since the APK could be uninstalled manually). 40 * <p/> 41 * Manually uninstalling an APK from a connected device will still be a problem, but this should 42 * be a limited use case. 43 * <p/> 44 * This is a singleton. To get the instance, use {@link #getInstance()} 45 */ 46 public class ApkInstallManager implements IDeviceChangeListener, IDebugBridgeChangeListener, 47 IProjectListener { 48 49 private final static ApkInstallManager sThis = new ApkInstallManager(); 50 51 /** 52 * Internal struct to associate a project and a device. 53 */ 54 private static class ApkInstall { ApkInstall(IProject project, IDevice device)55 public ApkInstall(IProject project, IDevice device) { 56 this.project = project; 57 this.device = device; 58 } 59 IProject project; 60 IDevice device; 61 } 62 63 private final ArrayList<ApkInstall> mInstallList = new ArrayList<ApkInstall>(); 64 getInstance()65 public static ApkInstallManager getInstance() { 66 return sThis; 67 } 68 69 /** 70 * Registers an installation of <var>project</var> onto <var>device</var> 71 * @param project The project that was installed. 72 * @param device The device that received the installation. 73 */ registerInstallation(IProject project, IDevice device)74 public void registerInstallation(IProject project, IDevice device) { 75 synchronized (mInstallList) { 76 mInstallList.add(new ApkInstall(project, device)); 77 } 78 } 79 80 /** 81 * Returns whether a <var>project</var> was installed on the <var>device</var>. 82 * @param project the project that may have been installed. 83 * @param device the device that may have received the installation. 84 * @return 85 */ isApplicationInstalled(IProject project, IDevice device)86 public boolean isApplicationInstalled(IProject project, IDevice device) { 87 synchronized (mInstallList) { 88 for (ApkInstall install : mInstallList) { 89 if (project == install.project && device == install.device) { 90 return true; 91 } 92 } 93 } 94 return false; 95 } 96 97 /** 98 * Resets registered installations for a specific {@link IProject}. 99 * <p/>This ensures that {@link #isApplicationInstalled(IProject, IDevice)} will always return 100 * <code>null</code> for this specified project, for any device. 101 * @param project the project for which to reset all installations. 102 */ resetInstallationFor(IProject project)103 public void resetInstallationFor(IProject project) { 104 synchronized (mInstallList) { 105 for (int i = 0 ; i < mInstallList.size() ;) { 106 ApkInstall install = mInstallList.get(i); 107 if (install.project == project) { 108 mInstallList.remove(i); 109 } else { 110 i++; 111 } 112 } 113 } 114 } 115 ApkInstallManager()116 private ApkInstallManager() { 117 AndroidDebugBridge.addDeviceChangeListener(this); 118 AndroidDebugBridge.addDebugBridgeChangeListener(this); 119 ResourceMonitor.getMonitor().addProjectListener(this); 120 } 121 122 /* 123 * Responds to a bridge change by clearing the full installation list. 124 * (non-Javadoc) 125 * @see com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener#bridgeChanged(com.android.ddmlib.AndroidDebugBridge) 126 */ bridgeChanged(AndroidDebugBridge bridge)127 public void bridgeChanged(AndroidDebugBridge bridge) { 128 // the bridge changed, there is no way to know which IDevice will be which. 129 // We reset everything 130 synchronized (mInstallList) { 131 mInstallList.clear(); 132 } 133 } 134 135 /* 136 * Responds to a device being disconnected by removing all installations related to this device. 137 * (non-Javadoc) 138 * @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceDisconnected(com.android.ddmlib.Device) 139 */ deviceDisconnected(IDevice device)140 public void deviceDisconnected(IDevice device) { 141 synchronized (mInstallList) { 142 for (int i = 0 ; i < mInstallList.size() ;) { 143 ApkInstall install = mInstallList.get(i); 144 if (install.device == device) { 145 mInstallList.remove(i); 146 } else { 147 i++; 148 } 149 } 150 } 151 } 152 153 /* 154 * Responds to a close project by resetting all its installation. 155 * (non-Javadoc) 156 * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectClosed(org.eclipse.core.resources.IProject) 157 */ projectClosed(IProject project)158 public void projectClosed(IProject project) { 159 resetInstallationFor(project); 160 } 161 162 /* 163 * Responds to a close project by resetting all its installation. 164 * (non-Javadoc) 165 * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectDeleted(org.eclipse.core.resources.IProject) 166 */ projectDeleted(IProject project)167 public void projectDeleted(IProject project) { 168 resetInstallationFor(project); 169 } 170 171 /* 172 * Does nothing 173 * (non-Javadoc) 174 * @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceChanged(com.android.ddmlib.Device, int) 175 */ deviceChanged(IDevice device, int changeMask)176 public void deviceChanged(IDevice device, int changeMask) { 177 // nothing to do. 178 } 179 180 /* 181 * Does nothing 182 * (non-Javadoc) 183 * @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceConnected(com.android.ddmlib.Device) 184 */ deviceConnected(IDevice device)185 public void deviceConnected(IDevice device) { 186 // nothing to do. 187 } 188 189 /* 190 * Does nothing 191 * (non-Javadoc) 192 * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectOpened(org.eclipse.core.resources.IProject) 193 */ projectOpened(IProject project)194 public void projectOpened(IProject project) { 195 // nothing to do. 196 } 197 198 /* 199 * Does nothing 200 * (non-Javadoc) 201 * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectOpenedWithWorkspace(org.eclipse.core.resources.IProject) 202 */ projectOpenedWithWorkspace(IProject project)203 public void projectOpenedWithWorkspace(IProject project) { 204 // nothing to do. 205 } 206 } 207