Home | History | Annotate | Download | only in device
      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