• 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.models;
18 
19 import com.android.ddmlib.IDevice;
20 import com.android.hierarchyviewerlib.device.DeviceBridge.ViewServerInfo;
21 import com.android.hierarchyviewerlib.device.Window;
22 
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 
26 /**
27  * This class stores the list of windows for each connected device. It notifies
28  * listeners of any changes as well as knows which window is currently selected
29  * in the device selector.
30  */
31 public class DeviceSelectionModel {
32 
33     private final HashMap<IDevice, DeviceInfo> mDeviceMap = new HashMap<IDevice, DeviceInfo>();
34 
35     private final HashMap<IDevice, Integer> mFocusedWindowHashes = new HashMap<IDevice, Integer>();
36 
37     private final ArrayList<IDevice> mDeviceList = new ArrayList<IDevice>();
38 
39     private final ArrayList<IWindowChangeListener> mWindowChangeListeners =
40             new ArrayList<IWindowChangeListener>();
41 
42     private IDevice mSelectedDevice;
43 
44     private Window mSelectedWindow;
45 
46     private static DeviceSelectionModel sModel;
47 
48     private static class DeviceInfo {
49         Window[] windows;
50         ViewServerInfo viewServerInfo;
51 
DeviceInfo(Window[] windows, ViewServerInfo viewServerInfo)52         private DeviceInfo(Window[] windows, ViewServerInfo viewServerInfo) {
53             this.windows = windows;
54             this.viewServerInfo = viewServerInfo;
55         }
56     }
getModel()57     public static DeviceSelectionModel getModel() {
58         if (sModel == null) {
59             sModel = new DeviceSelectionModel();
60         }
61         return sModel;
62     }
63 
containsDevice(IDevice device)64     public boolean containsDevice(IDevice device) {
65         synchronized (mDeviceMap) {
66             return mDeviceMap.containsKey(device);
67         }
68     }
69 
addDevice(IDevice device, Window[] windows, ViewServerInfo info)70     public void addDevice(IDevice device, Window[] windows, ViewServerInfo info) {
71         synchronized (mDeviceMap) {
72             mDeviceMap.put(device, new DeviceInfo(windows, info));
73             mDeviceList.add(device);
74         }
75         notifyDeviceConnected(device);
76     }
77 
removeDevice(IDevice device)78     public void removeDevice(IDevice device) {
79         boolean selectionChanged = false;
80         synchronized (mDeviceMap) {
81             mDeviceList.remove(device);
82             if (!mDeviceList.contains(device)) {
83                 mDeviceMap.remove(device);
84                 mFocusedWindowHashes.remove(device);
85                 if (mSelectedDevice == device) {
86                     mSelectedDevice = null;
87                     mSelectedWindow = null;
88                     selectionChanged = true;
89                 }
90             }
91         }
92         notifyDeviceDisconnected(device);
93         if (selectionChanged) {
94             notifySelectionChanged(mSelectedDevice, mSelectedWindow);
95         }
96     }
97 
updateDevice(IDevice device, Window[] windows)98     public void updateDevice(IDevice device, Window[] windows) {
99         boolean selectionChanged = false;
100         synchronized (mDeviceMap) {
101             DeviceInfo oldDeviceInfo = mDeviceMap.get(device);
102             ViewServerInfo oldViewServerInfo = null;
103             if (oldDeviceInfo != null) {
104                 oldViewServerInfo = oldDeviceInfo.viewServerInfo;
105             }
106             mDeviceMap.put(device, new DeviceInfo(windows, oldViewServerInfo));
107             // If the selected window no longer exists, we clear the selection.
108             if (mSelectedDevice == device && mSelectedWindow != null) {
109                 boolean windowStillExists = false;
110                 for (int i = 0; i < windows.length && !windowStillExists; i++) {
111                     if (windows[i].equals(mSelectedWindow)) {
112                         windowStillExists = true;
113                     }
114                 }
115                 if (!windowStillExists) {
116                     mSelectedDevice = null;
117                     mSelectedWindow = null;
118                     selectionChanged = true;
119                 }
120             }
121         }
122         notifyDeviceChanged(device);
123         if (selectionChanged) {
124             notifySelectionChanged(mSelectedDevice, mSelectedWindow);
125         }
126     }
127 
128     /*
129      * Change which window has focus and notify the listeners.
130      */
updateFocusedWindow(IDevice device, int focusedWindow)131     public void updateFocusedWindow(IDevice device, int focusedWindow) {
132         Integer oldValue = null;
133         synchronized (mDeviceMap) {
134             oldValue = mFocusedWindowHashes.put(device, new Integer(focusedWindow));
135         }
136         // Only notify if the values are different. It would be cool if Java
137         // containers accepted basic types like int.
138         if (oldValue == null || (oldValue != null && oldValue.intValue() != focusedWindow)) {
139             notifyFocusChanged(device);
140         }
141     }
142 
143     public static interface IWindowChangeListener {
deviceConnected(IDevice device)144         public void deviceConnected(IDevice device);
145 
deviceChanged(IDevice device)146         public void deviceChanged(IDevice device);
147 
deviceDisconnected(IDevice device)148         public void deviceDisconnected(IDevice device);
149 
focusChanged(IDevice device)150         public void focusChanged(IDevice device);
151 
selectionChanged(IDevice device, Window window)152         public void selectionChanged(IDevice device, Window window);
153     }
154 
getWindowChangeListenerList()155     private IWindowChangeListener[] getWindowChangeListenerList() {
156         IWindowChangeListener[] listeners = null;
157         synchronized (mWindowChangeListeners) {
158             if (mWindowChangeListeners.size() == 0) {
159                 return null;
160             }
161             listeners =
162                     mWindowChangeListeners.toArray(new IWindowChangeListener[mWindowChangeListeners
163                             .size()]);
164         }
165         return listeners;
166     }
167 
notifyDeviceConnected(IDevice device)168     private void notifyDeviceConnected(IDevice device) {
169         IWindowChangeListener[] listeners = getWindowChangeListenerList();
170         if (listeners != null) {
171             for (int i = 0; i < listeners.length; i++) {
172                 listeners[i].deviceConnected(device);
173             }
174         }
175     }
176 
notifyDeviceChanged(IDevice device)177     private void notifyDeviceChanged(IDevice device) {
178         IWindowChangeListener[] listeners = getWindowChangeListenerList();
179         if (listeners != null) {
180             for (int i = 0; i < listeners.length; i++) {
181                 listeners[i].deviceChanged(device);
182             }
183         }
184     }
185 
notifyDeviceDisconnected(IDevice device)186     private void notifyDeviceDisconnected(IDevice device) {
187         IWindowChangeListener[] listeners = getWindowChangeListenerList();
188         if (listeners != null) {
189             for (int i = 0; i < listeners.length; i++) {
190                 listeners[i].deviceDisconnected(device);
191             }
192         }
193     }
194 
notifyFocusChanged(IDevice device)195     private void notifyFocusChanged(IDevice device) {
196         IWindowChangeListener[] listeners = getWindowChangeListenerList();
197         if (listeners != null) {
198             for (int i = 0; i < listeners.length; i++) {
199                 listeners[i].focusChanged(device);
200             }
201         }
202     }
203 
notifySelectionChanged(IDevice device, Window window)204     private void notifySelectionChanged(IDevice device, Window window) {
205         IWindowChangeListener[] listeners = getWindowChangeListenerList();
206         if (listeners != null) {
207             for (int i = 0; i < listeners.length; i++) {
208                 listeners[i].selectionChanged(device, window);
209             }
210         }
211     }
212 
addWindowChangeListener(IWindowChangeListener listener)213     public void addWindowChangeListener(IWindowChangeListener listener) {
214         synchronized (mWindowChangeListeners) {
215             mWindowChangeListeners.add(listener);
216         }
217     }
218 
removeWindowChangeListener(IWindowChangeListener listener)219     public void removeWindowChangeListener(IWindowChangeListener listener) {
220         synchronized (mWindowChangeListeners) {
221             mWindowChangeListeners.remove(listener);
222         }
223     }
224 
getDevices()225     public IDevice[] getDevices() {
226         synchronized (mDeviceMap) {
227             return mDeviceList.toArray(new IDevice[mDeviceList.size()]);
228         }
229     }
230 
getWindows(IDevice device)231     public Window[] getWindows(IDevice device) {
232         Window[] windows = null;
233         synchronized (mDeviceMap) {
234             DeviceInfo info = mDeviceMap.get(device);
235             if (info != null) {
236                 windows = mDeviceMap.get(device).windows;
237             }
238         }
239         return windows;
240     }
241 
242     // Returns the window that currently has focus or -1. Note that this means
243     // that a window with hashcode -1 gets highlighted. If you remember, this is
244     // the infamous <Focused Window>
getFocusedWindow(IDevice device)245     public int getFocusedWindow(IDevice device) {
246         synchronized (mDeviceMap) {
247             Integer focusedWindow = mFocusedWindowHashes.get(device);
248             if (focusedWindow == null) {
249                 return -1;
250             }
251             return focusedWindow.intValue();
252         }
253     }
254 
setSelection(IDevice device, Window window)255     public void setSelection(IDevice device, Window window) {
256         synchronized (mDeviceMap) {
257             mSelectedDevice = device;
258             mSelectedWindow = window;
259         }
260         notifySelectionChanged(device, window);
261     }
262 
getSelectedDevice()263     public IDevice getSelectedDevice() {
264         synchronized (mDeviceMap) {
265             return mSelectedDevice;
266         }
267     }
268 
getSelectedWindow()269     public Window getSelectedWindow() {
270         synchronized (mDeviceMap) {
271             return mSelectedWindow;
272         }
273     }
274 
getSelectedDeviceInfo()275     public ViewServerInfo getSelectedDeviceInfo() {
276         synchronized (mDeviceMap) {
277             ViewServerInfo viewServerInfo = null;
278             if (mSelectedDevice != null) {
279                 return mDeviceMap.get(mSelectedDevice).viewServerInfo;
280             }
281             return null;
282         }
283     }
284 
285 }
286