PageRenderTime 52ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ApkInstallManager.java

https://gitlab.com/Codeaurora/platform_sdk
Java | 263 lines | 143 code | 31 blank | 89 comment | 20 complexity | d4be4491b8c52ed30f63cc316c39a1b0 MD5 | raw file
  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. package com.android.ide.eclipse.adt.internal.project;
  17. import com.android.ddmlib.AndroidDebugBridge;
  18. import com.android.ddmlib.IDevice;
  19. import com.android.ddmlib.MultiLineReceiver;
  20. import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener;
  21. import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
  22. import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor;
  23. import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IProjectListener;
  24. import org.eclipse.core.resources.IProject;
  25. import org.eclipse.core.runtime.IPath;
  26. import java.util.HashSet;
  27. import java.util.Iterator;
  28. /**
  29. * Registers which apk was installed on which device.
  30. * <p/>
  31. * The goal of this class is to remember the installation of APKs on devices, and provide
  32. * information about whether a new APK should be installed on a device prior to running the
  33. * application from a launch configuration.
  34. * <p/>
  35. * The manager uses {@link IProject} and {@link IDevice} to identify the target device and the
  36. * (project generating the) APK. This ensures that disconnected and reconnected devices will
  37. * always receive new APKs (since the version may not match).
  38. * <p/>
  39. * This is a singleton. To get the instance, use {@link #getInstance()}
  40. */
  41. public final class ApkInstallManager {
  42. private final static ApkInstallManager sThis = new ApkInstallManager();
  43. /**
  44. * Internal struct to associate a project and a device.
  45. */
  46. private final static class ApkInstall {
  47. public ApkInstall(IProject project, String packageName, IDevice device) {
  48. this.project = project;
  49. this.packageName = packageName;
  50. this.device = device;
  51. }
  52. @Override
  53. public boolean equals(Object obj) {
  54. if (obj instanceof ApkInstall) {
  55. ApkInstall apkObj = (ApkInstall)obj;
  56. return (device == apkObj.device && project.equals(apkObj.project) &&
  57. packageName.equals(apkObj.packageName));
  58. }
  59. return false;
  60. }
  61. @Override
  62. public int hashCode() {
  63. return (device.getSerialNumber() + project.getName() + packageName).hashCode();
  64. }
  65. final IProject project;
  66. final String packageName;
  67. final IDevice device;
  68. }
  69. /**
  70. * Receiver and parser for the "pm path package" command.
  71. */
  72. private final static class PmReceiver extends MultiLineReceiver {
  73. boolean foundPackage = false;
  74. @Override
  75. public void processNewLines(String[] lines) {
  76. // if the package if found, then pm will show a line starting with "package:/"
  77. if (foundPackage == false) { // just in case this is called several times for multilines
  78. for (String line : lines) {
  79. if (line.startsWith("package:/")) {
  80. foundPackage = true;
  81. break;
  82. }
  83. }
  84. }
  85. }
  86. public boolean isCancelled() {
  87. return false;
  88. }
  89. }
  90. /**
  91. * Hashset of the list of installed package. Hashset used to ensure we don't re-add new
  92. * objects for the same app.
  93. */
  94. private final HashSet<ApkInstall> mInstallList = new HashSet<ApkInstall>();
  95. public static ApkInstallManager getInstance() {
  96. return sThis;
  97. }
  98. /**
  99. * Registers an installation of <var>project</var> onto <var>device</var>
  100. * @param project The project that was installed.
  101. * @param packageName the package name of the apk
  102. * @param device The device that received the installation.
  103. */
  104. public void registerInstallation(IProject project, String packageName, IDevice device) {
  105. synchronized (mInstallList) {
  106. mInstallList.add(new ApkInstall(project, packageName, device));
  107. }
  108. }
  109. /**
  110. * Returns whether a <var>project</var> was installed on the <var>device</var>.
  111. * @param project the project that may have been installed.
  112. * @param device the device that may have received the installation.
  113. * @return
  114. */
  115. public boolean isApplicationInstalled(IProject project, String packageName, IDevice device) {
  116. synchronized (mInstallList) {
  117. ApkInstall found = null;
  118. for (ApkInstall install : mInstallList) {
  119. if (project.equals(install.project) && packageName.equals(install.packageName) &&
  120. device == install.device) {
  121. found = install;
  122. break;
  123. }
  124. }
  125. // check the app is still installed.
  126. if (found != null) {
  127. try {
  128. PmReceiver receiver = new PmReceiver();
  129. found.device.executeShellCommand("pm path " + packageName, receiver);
  130. if (receiver.foundPackage == false) {
  131. mInstallList.remove(found);
  132. }
  133. return receiver.foundPackage;
  134. } catch (Exception e) {
  135. // failed to query pm? force reinstall.
  136. return false;
  137. }
  138. }
  139. }
  140. return false;
  141. }
  142. /**
  143. * Resets registered installations for a specific {@link IProject}.
  144. * <p/>This ensures that {@link #isApplicationInstalled(IProject, IDevice)} will always return
  145. * <code>null</code> for this specified project, for any device.
  146. * @param project the project for which to reset all installations.
  147. */
  148. public void resetInstallationFor(IProject project) {
  149. synchronized (mInstallList) {
  150. Iterator<ApkInstall> iterator = mInstallList.iterator();
  151. while (iterator.hasNext()) {
  152. ApkInstall install = iterator.next();
  153. if (install.project.equals(project)) {
  154. iterator.remove();
  155. }
  156. }
  157. }
  158. }
  159. private ApkInstallManager() {
  160. AndroidDebugBridge.addDeviceChangeListener(mDeviceChangeListener);
  161. AndroidDebugBridge.addDebugBridgeChangeListener(mDebugBridgeListener);
  162. GlobalProjectMonitor.getMonitor().addProjectListener(mProjectListener);
  163. }
  164. private IDebugBridgeChangeListener mDebugBridgeListener = new IDebugBridgeChangeListener() {
  165. /**
  166. * Responds to a bridge change by clearing the full installation list.
  167. *
  168. * @see IDebugBridgeChangeListener#bridgeChanged(AndroidDebugBridge)
  169. */
  170. public void bridgeChanged(AndroidDebugBridge bridge) {
  171. // the bridge changed, there is no way to know which IDevice will be which.
  172. // We reset everything
  173. synchronized (mInstallList) {
  174. mInstallList.clear();
  175. }
  176. }
  177. };
  178. private IDeviceChangeListener mDeviceChangeListener = new IDeviceChangeListener() {
  179. /**
  180. * Responds to a device being disconnected by removing all installations related
  181. * to this device.
  182. *
  183. * @see IDeviceChangeListener#deviceDisconnected(IDevice)
  184. */
  185. public void deviceDisconnected(IDevice device) {
  186. synchronized (mInstallList) {
  187. Iterator<ApkInstall> iterator = mInstallList.iterator();
  188. while (iterator.hasNext()) {
  189. ApkInstall install = iterator.next();
  190. if (install.device == device) {
  191. iterator.remove();
  192. }
  193. }
  194. }
  195. }
  196. public void deviceChanged(IDevice device, int changeMask) {
  197. // nothing to do.
  198. }
  199. public void deviceConnected(IDevice device) {
  200. // nothing to do.
  201. }
  202. };
  203. private IProjectListener mProjectListener = new IProjectListener() {
  204. /**
  205. * Responds to a closed project by resetting all its installation.
  206. *
  207. * @see IProjectListener#projectClosed(IProject)
  208. */
  209. public void projectClosed(IProject project) {
  210. resetInstallationFor(project);
  211. }
  212. /**
  213. * Responds to a deleted project by resetting all its installation.
  214. *
  215. * @see IProjectListener#projectDeleted(IProject)
  216. */
  217. public void projectDeleted(IProject project) {
  218. resetInstallationFor(project);
  219. }
  220. public void projectOpened(IProject project) {
  221. // nothing to do.
  222. }
  223. public void projectOpenedWithWorkspace(IProject project) {
  224. // nothing to do.
  225. }
  226. public void projectRenamed(IProject project, IPath from) {
  227. // project renaming also triggers delete/open events so
  228. // there's nothing to do here (since delete will remove
  229. // whatever's linked to the project from the list).
  230. }
  231. };
  232. }