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