/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import java.util.HashMap; /** * Safe identifier for a window. This currently allows you to retrieve and observe * the input focus state of the window. Most applications will * not use this, instead relying on the simpler (and more efficient) methods available * on {@link View}. This classes is useful when window input interactions need to be * done across processes: the class itself is a Parcelable that can be passed to other * processes for them to interact with your window, and it provides a limited safe API * that doesn't allow the other process to negatively harm your window. */ public class WindowId implements Parcelable { private final IWindowId mToken; /** * Subclass for observing changes to the focus state of an {@link WindowId}. * You should use the same instance of this class for observing multiple * {@link WindowId} objects, since this class is fairly heavy-weight -- the * base class includes all of the mechanisms for connecting to and receiving updates * from the window. */ public static abstract class FocusObserver { final IWindowFocusObserver.Stub mIObserver = new IWindowFocusObserver.Stub() { @Override public void focusGained(IBinder inputToken) { WindowId token; synchronized (mRegistrations) { token = mRegistrations.get(inputToken); } if (mHandler != null) { mHandler.sendMessage(mHandler.obtainMessage(1, token)); } else { onFocusGained(token); } } @Override public void focusLost(IBinder inputToken) { WindowId token; synchronized (mRegistrations) { token = mRegistrations.get(inputToken); } if (mHandler != null) { mHandler.sendMessage(mHandler.obtainMessage(2, token)); } else { onFocusLost(token); } } }; final HashMap mRegistrations = new HashMap(); class H extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: onFocusGained((WindowId)msg.obj); break; case 2: onFocusLost((WindowId)msg.obj); break; default: super.handleMessage(msg); } } } final Handler mHandler; /** * Construct a new observer. This observer will be configured so that all * of its callbacks are dispatched on the current calling thread. */ public FocusObserver() { mHandler = new H(); } /** * Called when one of the monitored windows gains input focus. */ public abstract void onFocusGained(WindowId token); /** * Called when one of the monitored windows loses input focus. */ public abstract void onFocusLost(WindowId token); } /** * Retrieve the current focus state of the associated window. */ public boolean isFocused() { try { return mToken.isFocused(); } catch (RemoteException e) { return false; } } /** * Start monitoring for changes in the focus state of the window. */ public void registerFocusObserver(FocusObserver observer) { synchronized (observer.mRegistrations) { if (observer.mRegistrations.containsKey(mToken.asBinder())) { throw new IllegalStateException( "Focus observer already registered with input token"); } observer.mRegistrations.put(mToken.asBinder(), this); try { mToken.registerFocusObserver(observer.mIObserver); } catch (RemoteException e) { } } } /** * Stop monitoring changes in the focus state of the window. */ public void unregisterFocusObserver(FocusObserver observer) { synchronized (observer.mRegistrations) { if (observer.mRegistrations.remove(mToken.asBinder()) == null) { throw new IllegalStateException("Focus observer not registered with input token"); } try { mToken.unregisterFocusObserver(observer.mIObserver); } catch (RemoteException e) { } } } /** * Comparison operator on two IntentSender objects, such that true * is returned then they both represent the same operation from the * same package. */ @Override public boolean equals(Object otherObj) { if (otherObj instanceof WindowId) { return mToken.asBinder().equals(((WindowId) otherObj) .mToken.asBinder()); } return false; } @Override public int hashCode() { return mToken.asBinder().hashCode(); } @Override public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("IntentSender{"); sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(": "); sb.append(mToken != null ? mToken.asBinder() : null); sb.append('}'); return sb.toString(); } public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { out.writeStrongBinder(mToken.asBinder()); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public WindowId createFromParcel(Parcel in) { IBinder target = in.readStrongBinder(); return target != null ? new WindowId(target) : null; } public WindowId[] newArray(int size) { return new WindowId[size]; } }; /** @hide */ public IWindowId getTarget() { return mToken; } /** @hide */ public WindowId(IWindowId target) { mToken = target; } /** @hide */ public WindowId(IBinder target) { mToken = IWindowId.Stub.asInterface(target); } }