blob: c4cda2c70f25658a46d7cf445f1a26fdf0132a2a [file] [log] [blame]
Dianne Hackborne3f23a32013-03-01 13:25:35 -08001/*
2 * Copyright (C) 2006 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
17package android.view;
18
19import android.os.Handler;
20import android.os.IBinder;
21import android.os.Message;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.os.RemoteException;
25
26import java.util.HashMap;
27
28/**
29 * Safe identifier for a window. This currently allows you to retrieve and observe
30 * the input focus state of the window. Most applications will
31 * not use this, instead relying on the simpler (and more efficient) methods available
32 * on {@link View}. This classes is useful when window input interactions need to be
33 * done across processes: the class itself is a Parcelable that can be passed to other
34 * processes for them to interact with your window, and it provides a limited safe API
35 * that doesn't allow the other process to negatively harm your window.
36 */
37public class WindowId implements Parcelable {
38 private final IWindowId mToken;
39
40 /**
41 * Subclass for observing changes to the focus state of an {@link WindowId}.
42 * You should use the same instance of this class for observing multiple
43 * {@link WindowId} objects, since this class is fairly heavy-weight -- the
44 * base class includes all of the mechanisms for connecting to and receiving updates
45 * from the window.
46 */
47 public static abstract class FocusObserver {
48 final IWindowFocusObserver.Stub mIObserver = new IWindowFocusObserver.Stub() {
49
50 @Override
51 public void focusGained(IBinder inputToken) {
52 WindowId token;
53 synchronized (mRegistrations) {
54 token = mRegistrations.get(inputToken);
55 }
56 if (mHandler != null) {
57 mHandler.sendMessage(mHandler.obtainMessage(1, token));
58 } else {
59 onFocusGained(token);
60 }
61 }
62
63 @Override
64 public void focusLost(IBinder inputToken) {
65 WindowId token;
66 synchronized (mRegistrations) {
67 token = mRegistrations.get(inputToken);
68 }
69 if (mHandler != null) {
70 mHandler.sendMessage(mHandler.obtainMessage(2, token));
71 } else {
72 onFocusLost(token);
73 }
74 }
75 };
76
77 final HashMap<IBinder, WindowId> mRegistrations
78 = new HashMap<IBinder, WindowId>();
79
80 class H extends Handler {
81 @Override
82 public void handleMessage(Message msg) {
83 switch (msg.what) {
84 case 1:
85 onFocusGained((WindowId)msg.obj);
86 break;
87 case 2:
88 onFocusLost((WindowId)msg.obj);
89 break;
90 default:
91 super.handleMessage(msg);
92 }
93 }
94 }
95
96 final Handler mHandler;
97
98 /**
99 * Construct a new observer. This observer will be configured so that all
100 * of its callbacks are dispatched on the current calling thread.
101 */
102 public FocusObserver() {
103 mHandler = new H();
104 }
105
106 /**
107 * Called when one of the monitored windows gains input focus.
108 */
109 public abstract void onFocusGained(WindowId token);
110
111 /**
112 * Called when one of the monitored windows loses input focus.
113 */
114 public abstract void onFocusLost(WindowId token);
115 }
116
117 /**
118 * Retrieve the current focus state of the associated window.
119 */
120 public boolean isFocused() {
121 try {
122 return mToken.isFocused();
123 } catch (RemoteException e) {
124 return false;
125 }
126 }
127
128 /**
129 * Start monitoring for changes in the focus state of the window.
130 */
131 public void registerFocusObserver(FocusObserver observer) {
132 synchronized (observer.mRegistrations) {
133 if (observer.mRegistrations.containsKey(mToken.asBinder())) {
134 throw new IllegalStateException(
135 "Focus observer already registered with input token");
136 }
137 observer.mRegistrations.put(mToken.asBinder(), this);
138 try {
139 mToken.registerFocusObserver(observer.mIObserver);
140 } catch (RemoteException e) {
141 }
142 }
143 }
144
145 /**
146 * Stop monitoring changes in the focus state of the window.
147 */
148 public void unregisterFocusObserver(FocusObserver observer) {
149 synchronized (observer.mRegistrations) {
150 if (observer.mRegistrations.remove(mToken.asBinder()) == null) {
151 throw new IllegalStateException("Focus observer not registered with input token");
152 }
153 try {
154 mToken.unregisterFocusObserver(observer.mIObserver);
155 } catch (RemoteException e) {
156 }
157 }
158 }
159
160 /**
161 * Comparison operator on two IntentSender objects, such that true
162 * is returned then they both represent the same operation from the
163 * same package.
164 */
165 @Override
166 public boolean equals(Object otherObj) {
167 if (otherObj instanceof WindowId) {
168 return mToken.asBinder().equals(((WindowId) otherObj)
169 .mToken.asBinder());
170 }
171 return false;
172 }
173
174 @Override
175 public int hashCode() {
176 return mToken.asBinder().hashCode();
177 }
178
179 @Override
180 public String toString() {
181 StringBuilder sb = new StringBuilder(128);
182 sb.append("IntentSender{");
183 sb.append(Integer.toHexString(System.identityHashCode(this)));
184 sb.append(": ");
185 sb.append(mToken != null ? mToken.asBinder() : null);
186 sb.append('}');
187 return sb.toString();
188 }
189
190 public int describeContents() {
191 return 0;
192 }
193
194 public void writeToParcel(Parcel out, int flags) {
195 out.writeStrongBinder(mToken.asBinder());
196 }
197
198 public static final Parcelable.Creator<WindowId> CREATOR
199 = new Parcelable.Creator<WindowId>() {
200 public WindowId createFromParcel(Parcel in) {
201 IBinder target = in.readStrongBinder();
202 return target != null ? new WindowId(target) : null;
203 }
204
205 public WindowId[] newArray(int size) {
206 return new WindowId[size];
207 }
208 };
209
210 /** @hide */
211 public IWindowId getTarget() {
212 return mToken;
213 }
214
215 /** @hide */
216 public WindowId(IWindowId target) {
217 mToken = target;
218 }
219
220 /** @hide */
221 public WindowId(IBinder target) {
222 mToken = IWindowId.Stub.asInterface(target);
223 }
224}