1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 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.hierarchyviewerlib.device; 18 19 import com.android.ddmlib.IDevice; 20 21 import java.io.IOException; 22 import java.util.ArrayList; 23 import java.util.HashMap; 24 25 /** 26 * This class handles automatic updating of the list of windows in the device 27 * selector for device with protocol version 3 or above of the view server. It 28 * connects to the devices, keeps the connection open and listens for messages. 29 * It notifies all it's listeners of changes. 30 */ 31 public class WindowUpdater { 32 private static HashMap<IDevice, ArrayList<IWindowChangeListener>> sWindowChangeListeners = 33 new HashMap<IDevice, ArrayList<IWindowChangeListener>>(); 34 35 private static HashMap<IDevice, Thread> sListeningThreads = new HashMap<IDevice, Thread>(); 36 37 public static interface IWindowChangeListener { 38 public void windowsChanged(IDevice device); 39 40 public void focusChanged(IDevice device); 41 } 42 43 public static void terminate() { 44 synchronized (sListeningThreads) { 45 for (IDevice device : sListeningThreads.keySet()) { 46 sListeningThreads.get(device).interrupt(); 47 48 } 49 } 50 } 51 52 public static void startListenForWindowChanges(IWindowChangeListener listener, IDevice device) { 53 synchronized (sWindowChangeListeners) { 54 // In this case, a listening thread already exists, so we don't need 55 // to create another one. 56 if (sWindowChangeListeners.containsKey(device)) { 57 sWindowChangeListeners.get(device).add(listener); 58 return; 59 } 60 ArrayList<IWindowChangeListener> listeners = new ArrayList<IWindowChangeListener>(); 61 listeners.add(listener); 62 sWindowChangeListeners.put(device, listeners); 63 } 64 // Start listening 65 Thread listeningThread = new Thread(new WindowChangeMonitor(device)); 66 synchronized (sListeningThreads) { 67 sListeningThreads.put(device, listeningThread); 68 } 69 listeningThread.start(); 70 } 71 72 public static void stopListenForWindowChanges(IWindowChangeListener listener, IDevice device) { 73 synchronized (sWindowChangeListeners) { 74 ArrayList<IWindowChangeListener> listeners = sWindowChangeListeners.get(device); 75 listeners.remove(listener); 76 // There are more listeners, so don't stop the listening thread. 77 if (listeners.size() != 0) { 78 return; 79 } 80 sWindowChangeListeners.remove(device); 81 } 82 // Everybody left, so the party's over! 83 Thread listeningThread; 84 synchronized (sListeningThreads) { 85 listeningThread = sListeningThreads.get(device); 86 sListeningThreads.remove(device); 87 } 88 listeningThread.interrupt(); 89 } 90 91 private static IWindowChangeListener[] getWindowChangeListenersAsArray(IDevice device) { 92 IWindowChangeListener[] listeners; 93 synchronized (sWindowChangeListeners) { 94 ArrayList<IWindowChangeListener> windowChangeListenerList = 95 sWindowChangeListeners.get(device); 96 if (windowChangeListenerList == null) { 97 return null; 98 } 99 listeners = 100 windowChangeListenerList 101 .toArray(new IWindowChangeListener[windowChangeListenerList.size()]); 102 } 103 return listeners; 104 } 105 106 public static void notifyWindowsChanged(IDevice device) { 107 IWindowChangeListener[] listeners = getWindowChangeListenersAsArray(device); 108 if (listeners != null) { 109 for (int i = 0; i < listeners.length; i++) { 110 listeners[i].windowsChanged(device); 111 } 112 } 113 } 114 115 public static void notifyFocusChanged(IDevice device) { 116 IWindowChangeListener[] listeners = getWindowChangeListenersAsArray(device); 117 if (listeners != null) { 118 for (int i = 0; i < listeners.length; i++) { 119 listeners[i].focusChanged(device); 120 } 121 } 122 } 123 124 private static class WindowChangeMonitor implements Runnable { 125 private IDevice device; 126 127 public WindowChangeMonitor(IDevice device) { 128 this.device = device; 129 } 130 131 public void run() { 132 while (!Thread.currentThread().isInterrupted()) { 133 DeviceConnection connection = null; 134 try { 135 connection = new DeviceConnection(device); 136 connection.sendCommand("AUTOLIST"); 137 String line; 138 while (!Thread.currentThread().isInterrupted() 139 && (line = connection.getInputStream().readLine()) != null) { 140 if (line.equalsIgnoreCase("LIST UPDATE")) { 141 notifyWindowsChanged(device); 142 } else if (line.equalsIgnoreCase("FOCUS UPDATE")) { 143 notifyFocusChanged(device); 144 } 145 } 146 147 } catch (IOException e) { 148 } finally { 149 if (connection != null) { 150 connection.close(); 151 } 152 } 153 } 154 } 155 } 156 } 157