• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
windowsChanged(IDevice device)38         public void windowsChanged(IDevice device);
39 
focusChanged(IDevice device)40         public void focusChanged(IDevice device);
41     }
42 
terminate()43     public static void terminate() {
44         synchronized (sListeningThreads) {
45             for (IDevice device : sListeningThreads.keySet()) {
46                 sListeningThreads.get(device).interrupt();
47 
48             }
49         }
50     }
51 
startListenForWindowChanges(IWindowChangeListener listener, IDevice device)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 
stopListenForWindowChanges(IWindowChangeListener listener, IDevice device)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 
getWindowChangeListenersAsArray(IDevice device)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 
notifyWindowsChanged(IDevice device)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 
notifyFocusChanged(IDevice device)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 
WindowChangeMonitor(IDevice device)127         public WindowChangeMonitor(IDevice device) {
128             this.device = device;
129         }
130 
131         @Override
run()132         public void run() {
133             while (!Thread.currentThread().isInterrupted()) {
134                 DeviceConnection connection = null;
135                 try {
136                     connection = new DeviceConnection(device);
137                     connection.sendCommand("AUTOLIST");
138                     String line;
139                     while (!Thread.currentThread().isInterrupted()
140                             && (line = connection.getInputStream().readLine()) != null) {
141                         if (line.equalsIgnoreCase("LIST UPDATE")) {
142                             notifyWindowsChanged(device);
143                         } else if (line.equalsIgnoreCase("FOCUS UPDATE")) {
144                             notifyFocusChanged(device);
145                         }
146                     }
147 
148                 } catch (IOException e) {
149                 } finally {
150                     if (connection != null) {
151                         connection.close();
152                     }
153                 }
154             }
155         }
156     }
157 }
158