/* * Copyright (C) 2007-2008 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.inputmethodservice; import android.annotation.MainThread; import android.annotation.NonNull; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodSession; import java.io.FileDescriptor; import java.io.PrintWriter; /** * AbstractInputMethodService provides a abstract base class for input methods. * Normal input method implementations will not derive from this directly, * instead building on top of {@link InputMethodService} or another more * complete base class. Be sure to read {@link InputMethod} for more * information on the basics of writing input methods. * *

This class combines a Service (representing the input method component * to the system with the InputMethod interface that input methods must * implement. This base class takes care of reporting your InputMethod from * the service when clients bind to it, but provides no standard implementation * of the InputMethod interface itself. Derived classes must implement that * interface. */ public abstract class AbstractInputMethodService extends Service implements KeyEvent.Callback { private InputMethod mInputMethod; final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState(); /** * Base class for derived classes to implement their {@link InputMethod} * interface. This takes care of basic maintenance of the input method, * but most behavior must be implemented in a derived class. */ public abstract class AbstractInputMethodImpl implements InputMethod { /** * Instantiate a new client session for the input method, by calling * back to {@link AbstractInputMethodService#onCreateInputMethodSessionInterface() * AbstractInputMethodService.onCreateInputMethodSessionInterface()}. */ @MainThread public void createSession(SessionCallback callback) { callback.sessionCreated(onCreateInputMethodSessionInterface()); } /** * Take care of enabling or disabling an existing session by calling its * {@link AbstractInputMethodSessionImpl#revokeSelf() * AbstractInputMethodSessionImpl.setEnabled()} method. */ @MainThread public void setSessionEnabled(InputMethodSession session, boolean enabled) { ((AbstractInputMethodSessionImpl)session).setEnabled(enabled); } /** * Take care of killing an existing session by calling its * {@link AbstractInputMethodSessionImpl#revokeSelf() * AbstractInputMethodSessionImpl.revokeSelf()} method. */ @MainThread public void revokeSession(InputMethodSession session) { ((AbstractInputMethodSessionImpl)session).revokeSelf(); } } /** * Base class for derived classes to implement their {@link InputMethodSession} * interface. This takes care of basic maintenance of the session, * but most behavior must be implemented in a derived class. */ public abstract class AbstractInputMethodSessionImpl implements InputMethodSession { boolean mEnabled = true; boolean mRevoked; /** * Check whether this session has been enabled by the system. If not * enabled, you should not execute any calls on to it. */ public boolean isEnabled() { return mEnabled; } /** * Check whether this session has been revoked by the system. Revoked * session is also always disabled, so there is generally no need to * explicitly check for this. */ public boolean isRevoked() { return mRevoked; } /** * Change the enabled state of the session. This only works if the * session has not been revoked. */ public void setEnabled(boolean enabled) { if (!mRevoked) { mEnabled = enabled; } } /** * Revoke the session from the client. This disabled the session, and * prevents it from ever being enabled again. */ public void revokeSelf() { mRevoked = true; mEnabled = false; } /** * Take care of dispatching incoming key events to the appropriate * callbacks on the service, and tell the client when this is done. */ @Override public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) { boolean handled = event.dispatch(AbstractInputMethodService.this, mDispatcherState, this); if (callback != null) { callback.finishedEvent(seq, handled); } } /** * Take care of dispatching incoming trackball events to the appropriate * callbacks on the service, and tell the client when this is done. */ @Override public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) { boolean handled = onTrackballEvent(event); if (callback != null) { callback.finishedEvent(seq, handled); } } /** * Take care of dispatching incoming generic motion events to the appropriate * callbacks on the service, and tell the client when this is done. */ @Override public void dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback) { boolean handled = onGenericMotionEvent(event); if (callback != null) { callback.finishedEvent(seq, handled); } } } /** * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} * for used for processing events from the target application. * Normally you will not need to use this directly, but * just use the standard high-level event callbacks like {@link #onKeyDown}. */ public KeyEvent.DispatcherState getKeyDispatcherState() { return mDispatcherState; } /** * Called by the framework during initialization, when the InputMethod * interface for this service needs to be created. */ public abstract AbstractInputMethodImpl onCreateInputMethodInterface(); /** * Called by the framework when a new InputMethodSession interface is * needed for a new client of the input method. */ public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); /** * Implement this to handle {@link android.os.Binder#dump Binder.dump()} * calls on your input method. */ @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { } @Override final public IBinder onBind(Intent intent) { if (mInputMethod == null) { mInputMethod = onCreateInputMethodInterface(); } return new IInputMethodWrapper(this, mInputMethod); } /** * Implement this to handle trackball events on your input method. * * @param event The motion event being received. * @return True if the event was handled in this function, false otherwise. * @see android.view.View#onTrackballEvent(MotionEvent) */ public boolean onTrackballEvent(MotionEvent event) { return false; } /** * Implement this to handle generic motion events on your input method. * * @param event The motion event being received. * @return True if the event was handled in this function, false otherwise. * @see android.view.View#onGenericMotionEvent(MotionEvent) */ public boolean onGenericMotionEvent(MotionEvent event) { return false; } /** * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * *

Default implementation does nothing.

* * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. * This cannot be {@code null}. * @param inputConnection {@link InputConnection} with which * {@link InputConnection#commitContent(InputContentInfo, int, android.os.Bundle)} will be * called. * @return {@code false} if we cannot allow a temporary access permission. * @hide */ public void exposeContent(@NonNull InputContentInfo inputContentInfo, @NonNull InputConnection inputConnection) { return; } /** * Called when the user took some actions that should be taken into consideration to update the * MRU list for input method rotation. * * @hide */ public void notifyUserActionIfNecessary() { } }