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
17package com.android.server.input;
18
19import android.view.Display;
20import com.android.internal.R;
21import com.android.internal.util.XmlUtils;
22import com.android.server.DisplayThread;
23import com.android.server.LocalServices;
24import com.android.server.Watchdog;
25
26import org.xmlpull.v1.XmlPullParser;
27
28import android.Manifest;
29import android.app.Notification;
30import android.app.NotificationManager;
31import android.app.PendingIntent;
32import android.bluetooth.BluetoothAdapter;
33import android.bluetooth.BluetoothDevice;
34import android.content.BroadcastReceiver;
35import android.content.ComponentName;
36import android.content.Context;
37import android.content.Intent;
38import android.content.IntentFilter;
39import android.content.pm.ActivityInfo;
40import android.content.pm.ApplicationInfo;
41import android.content.pm.PackageManager;
42import android.content.pm.ResolveInfo;
43import android.content.pm.PackageManager.NameNotFoundException;
44import android.content.res.Resources;
45import android.content.res.Resources.NotFoundException;
46import android.content.res.TypedArray;
47import android.content.res.XmlResourceParser;
48import android.database.ContentObserver;
49import android.hardware.display.DisplayViewport;
50import android.hardware.input.IInputDevicesChangedListener;
51import android.hardware.input.IInputManager;
52import android.hardware.input.InputDeviceIdentifier;
53import android.hardware.input.InputManager;
54import android.hardware.input.InputManagerInternal;
55import android.hardware.input.KeyboardLayout;
56import android.hardware.input.TouchCalibration;
57import android.os.Binder;
58import android.os.Bundle;
59import android.os.Environment;
60import android.os.Handler;
61import android.os.IBinder;
62import android.os.Looper;
63import android.os.Message;
64import android.os.MessageQueue;
65import android.os.Process;
66import android.os.RemoteException;
67import android.os.UserHandle;
68import android.provider.Settings;
69import android.provider.Settings.SettingNotFoundException;
70import android.util.Log;
71import android.util.Slog;
72import android.util.SparseArray;
73import android.util.Xml;
74import android.view.IInputFilter;
75import android.view.IInputFilterHost;
76import android.view.InputChannel;
77import android.view.InputDevice;
78import android.view.InputEvent;
79import android.view.KeyEvent;
80import android.view.PointerIcon;
81import android.view.Surface;
82import android.view.ViewConfiguration;
83import android.view.WindowManagerPolicy;
84import android.widget.Toast;
85
86import java.io.File;
87import java.io.FileDescriptor;
88import java.io.FileNotFoundException;
89import java.io.FileReader;
90import java.io.IOException;
91import java.io.InputStreamReader;
92import java.io.PrintWriter;
93import java.util.ArrayList;
94import java.util.HashMap;
95import java.util.HashSet;
96
97import libcore.io.Streams;
98import libcore.util.Objects;
99
100/*
101 * Wraps the C++ InputManager and provides its callbacks.
102 */
103public class InputManagerService extends IInputManager.Stub
104        implements Watchdog.Monitor {
105    static final String TAG = "InputManager";
106    static final boolean DEBUG = false;
107
108    private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
109
110    private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
111    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
112    private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
113    private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
114    private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
115
116    // Pointer to native input manager service object.
117    private final long mPtr;
118
119    private final Context mContext;
120    private final InputManagerHandler mHandler;
121
122    private WindowManagerCallbacks mWindowManagerCallbacks;
123    private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
124    private boolean mSystemReady;
125    private NotificationManager mNotificationManager;
126
127    // Persistent data store.  Must be locked each time during use.
128    private final PersistentDataStore mDataStore = new PersistentDataStore();
129
130    // List of currently registered input devices changed listeners by process id.
131    private Object mInputDevicesLock = new Object();
132    private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
133    private InputDevice[] mInputDevices = new InputDevice[0];
134    private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
135            new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
136    private final ArrayList<InputDevicesChangedListenerRecord>
137            mTempInputDevicesChangedListenersToNotify =
138                    new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
139    private final ArrayList<InputDevice>
140            mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
141    private boolean mKeyboardLayoutNotificationShown;
142    private PendingIntent mKeyboardLayoutIntent;
143    private Toast mSwitchedKeyboardLayoutToast;
144
145    // State for vibrator tokens.
146    private Object mVibratorLock = new Object();
147    private HashMap<IBinder, VibratorToken> mVibratorTokens =
148            new HashMap<IBinder, VibratorToken>();
149    private int mNextVibratorTokenValue;
150
151    // State for the currently installed input filter.
152    final Object mInputFilterLock = new Object();
153    IInputFilter mInputFilter; // guarded by mInputFilterLock
154    InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
155
156    private static native long nativeInit(InputManagerService service,
157            Context context, MessageQueue messageQueue);
158    private static native void nativeStart(long ptr);
159    private static native void nativeSetDisplayViewport(long ptr, boolean external,
160            int displayId, int rotation,
161            int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
162            int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
163            int deviceWidth, int deviceHeight);
164
165    private static native int nativeGetScanCodeState(long ptr,
166            int deviceId, int sourceMask, int scanCode);
167    private static native int nativeGetKeyCodeState(long ptr,
168            int deviceId, int sourceMask, int keyCode);
169    private static native int nativeGetSwitchState(long ptr,
170            int deviceId, int sourceMask, int sw);
171    private static native boolean nativeHasKeys(long ptr,
172            int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
173    private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
174            InputWindowHandle inputWindowHandle, boolean monitor);
175    private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
176    private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
177    private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
178            int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
179            int policyFlags);
180    private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
181    private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
182    private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
183    private static native void nativeSetFocusedApplication(long ptr,
184            InputApplicationHandle application);
185    private static native boolean nativeTransferTouchFocus(long ptr,
186            InputChannel fromChannel, InputChannel toChannel);
187    private static native void nativeSetPointerSpeed(long ptr, int speed);
188    private static native void nativeSetShowTouches(long ptr, boolean enabled);
189    private static native void nativeSetInteractive(long ptr, boolean interactive);
190    private static native void nativeReloadCalibration(long ptr);
191    private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
192            int repeat, int token);
193    private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
194    private static native void nativeReloadKeyboardLayouts(long ptr);
195    private static native void nativeReloadDeviceAliases(long ptr);
196    private static native String nativeDump(long ptr);
197    private static native void nativeMonitor(long ptr);
198
199    // Input event injection constants defined in InputDispatcher.h.
200    private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
201    private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
202    private static final int INPUT_EVENT_INJECTION_FAILED = 2;
203    private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
204
205    // Maximum number of milliseconds to wait for input event injection.
206    private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
207
208    // Key states (may be returned by queries about the current state of a
209    // particular key code, scan code or switch).
210
211    /** The key state is unknown or the requested key itself is not supported. */
212    public static final int KEY_STATE_UNKNOWN = -1;
213
214    /** The key is up. /*/
215    public static final int KEY_STATE_UP = 0;
216
217    /** The key is down. */
218    public static final int KEY_STATE_DOWN = 1;
219
220    /** The key is down but is a virtual key press that is being emulated by the system. */
221    public static final int KEY_STATE_VIRTUAL = 2;
222
223    /** Scan code: Mouse / trackball button. */
224    public static final int BTN_MOUSE = 0x110;
225
226    // Switch code values must match bionic/libc/kernel/common/linux/input.h
227    /** Switch code: Lid switch.  When set, lid is shut. */
228    public static final int SW_LID = 0x00;
229
230    /** Switch code: Keypad slide.  When set, keyboard is exposed. */
231    public static final int SW_KEYPAD_SLIDE = 0x0a;
232
233    /** Switch code: Headphone.  When set, headphone is inserted. */
234    public static final int SW_HEADPHONE_INSERT = 0x02;
235
236    /** Switch code: Microphone.  When set, microphone is inserted. */
237    public static final int SW_MICROPHONE_INSERT = 0x04;
238
239    /** Switch code: Line out.  When set, Line out (hi-Z) is inserted. */
240    public static final int SW_LINEOUT_INSERT = 0x06;
241
242    /** Switch code: Headphone/Microphone Jack.  When set, something is inserted. */
243    public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
244
245    /** Switch code: Camera lens cover. When set the lens is covered. */
246    public static final int SW_CAMERA_LENS_COVER = 0x09;
247
248    public static final int SW_LID_BIT = 1 << SW_LID;
249    public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
250    public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
251    public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
252    public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
253    public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
254    public static final int SW_JACK_BITS =
255            SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
256    public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
257
258    /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
259    final boolean mUseDevInputEventForAudioJack;
260
261    public InputManagerService(Context context) {
262        this.mContext = context;
263        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
264
265        mUseDevInputEventForAudioJack =
266                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
267        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
268                + mUseDevInputEventForAudioJack);
269        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
270
271        LocalServices.addService(InputManagerInternal.class, new LocalService());
272    }
273
274    public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
275        mWindowManagerCallbacks = callbacks;
276    }
277
278    public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
279        mWiredAccessoryCallbacks = callbacks;
280    }
281
282    public void start() {
283        Slog.i(TAG, "Starting input manager");
284        nativeStart(mPtr);
285
286        // Add ourself to the Watchdog monitors.
287        Watchdog.getInstance().addMonitor(this);
288
289        registerPointerSpeedSettingObserver();
290        registerShowTouchesSettingObserver();
291
292        mContext.registerReceiver(new BroadcastReceiver() {
293            @Override
294            public void onReceive(Context context, Intent intent) {
295                updatePointerSpeedFromSettings();
296                updateShowTouchesFromSettings();
297            }
298        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
299
300        updatePointerSpeedFromSettings();
301        updateShowTouchesFromSettings();
302    }
303
304    // TODO(BT) Pass in paramter for bluetooth system
305    public void systemRunning() {
306        if (DEBUG) {
307            Slog.d(TAG, "System ready.");
308        }
309        mNotificationManager = (NotificationManager)mContext.getSystemService(
310                Context.NOTIFICATION_SERVICE);
311        mSystemReady = true;
312
313        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
314        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
315        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
316        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
317        filter.addDataScheme("package");
318        mContext.registerReceiver(new BroadcastReceiver() {
319            @Override
320            public void onReceive(Context context, Intent intent) {
321                updateKeyboardLayouts();
322            }
323        }, filter, null, mHandler);
324
325        filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
326        mContext.registerReceiver(new BroadcastReceiver() {
327            @Override
328            public void onReceive(Context context, Intent intent) {
329                reloadDeviceAliases();
330            }
331        }, filter, null, mHandler);
332
333        mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
334        mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
335
336        if (mWiredAccessoryCallbacks != null) {
337            mWiredAccessoryCallbacks.systemReady();
338        }
339    }
340
341    private void reloadKeyboardLayouts() {
342        if (DEBUG) {
343            Slog.d(TAG, "Reloading keyboard layouts.");
344        }
345        nativeReloadKeyboardLayouts(mPtr);
346    }
347
348    private void reloadDeviceAliases() {
349        if (DEBUG) {
350            Slog.d(TAG, "Reloading device names.");
351        }
352        nativeReloadDeviceAliases(mPtr);
353    }
354
355    private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
356            DisplayViewport externalTouchViewport) {
357        if (defaultViewport.valid) {
358            setDisplayViewport(false, defaultViewport);
359        }
360
361        if (externalTouchViewport.valid) {
362            setDisplayViewport(true, externalTouchViewport);
363        } else if (defaultViewport.valid) {
364            setDisplayViewport(true, defaultViewport);
365        }
366    }
367
368    private void setDisplayViewport(boolean external, DisplayViewport viewport) {
369        nativeSetDisplayViewport(mPtr, external,
370                viewport.displayId, viewport.orientation,
371                viewport.logicalFrame.left, viewport.logicalFrame.top,
372                viewport.logicalFrame.right, viewport.logicalFrame.bottom,
373                viewport.physicalFrame.left, viewport.physicalFrame.top,
374                viewport.physicalFrame.right, viewport.physicalFrame.bottom,
375                viewport.deviceWidth, viewport.deviceHeight);
376    }
377
378    /**
379     * Gets the current state of a key or button by key code.
380     * @param deviceId The input device id, or -1 to consult all devices.
381     * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
382     * consider all input sources.  An input device is consulted if at least one of its
383     * non-class input source bits matches the specified source mask.
384     * @param keyCode The key code to check.
385     * @return The key state.
386     */
387    public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
388        return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
389    }
390
391    /**
392     * Gets the current state of a key or button by scan code.
393     * @param deviceId The input device id, or -1 to consult all devices.
394     * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
395     * consider all input sources.  An input device is consulted if at least one of its
396     * non-class input source bits matches the specified source mask.
397     * @param scanCode The scan code to check.
398     * @return The key state.
399     */
400    public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
401        return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
402    }
403
404    /**
405     * Gets the current state of a switch by switch code.
406     * @param deviceId The input device id, or -1 to consult all devices.
407     * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
408     * consider all input sources.  An input device is consulted if at least one of its
409     * non-class input source bits matches the specified source mask.
410     * @param switchCode The switch code to check.
411     * @return The switch state.
412     */
413    public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
414        return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
415    }
416
417    /**
418     * Determines whether the specified key codes are supported by a particular device.
419     * @param deviceId The input device id, or -1 to consult all devices.
420     * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
421     * consider all input sources.  An input device is consulted if at least one of its
422     * non-class input source bits matches the specified source mask.
423     * @param keyCodes The array of key codes to check.
424     * @param keyExists An array at least as large as keyCodes whose entries will be set
425     * to true or false based on the presence or absence of support for the corresponding
426     * key codes.
427     * @return True if the lookup was successful, false otherwise.
428     */
429    @Override // Binder call
430    public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
431        if (keyCodes == null) {
432            throw new IllegalArgumentException("keyCodes must not be null.");
433        }
434        if (keyExists == null || keyExists.length < keyCodes.length) {
435            throw new IllegalArgumentException("keyExists must not be null and must be at "
436                    + "least as large as keyCodes.");
437        }
438
439        return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
440    }
441
442    /**
443     * Creates an input channel that will receive all input from the input dispatcher.
444     * @param inputChannelName The input channel name.
445     * @return The input channel.
446     */
447    public InputChannel monitorInput(String inputChannelName) {
448        if (inputChannelName == null) {
449            throw new IllegalArgumentException("inputChannelName must not be null.");
450        }
451
452        InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
453        nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
454        inputChannels[0].dispose(); // don't need to retain the Java object reference
455        return inputChannels[1];
456    }
457
458    /**
459     * Registers an input channel so that it can be used as an input event target.
460     * @param inputChannel The input channel to register.
461     * @param inputWindowHandle The handle of the input window associated with the
462     * input channel, or null if none.
463     */
464    public void registerInputChannel(InputChannel inputChannel,
465            InputWindowHandle inputWindowHandle) {
466        if (inputChannel == null) {
467            throw new IllegalArgumentException("inputChannel must not be null.");
468        }
469
470        nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
471    }
472
473    /**
474     * Unregisters an input channel.
475     * @param inputChannel The input channel to unregister.
476     */
477    public void unregisterInputChannel(InputChannel inputChannel) {
478        if (inputChannel == null) {
479            throw new IllegalArgumentException("inputChannel must not be null.");
480        }
481
482        nativeUnregisterInputChannel(mPtr, inputChannel);
483    }
484
485    /**
486     * Sets an input filter that will receive all input events before they are dispatched.
487     * The input filter may then reinterpret input events or inject new ones.
488     *
489     * To ensure consistency, the input dispatcher automatically drops all events
490     * in progress whenever an input filter is installed or uninstalled.  After an input
491     * filter is uninstalled, it can no longer send input events unless it is reinstalled.
492     * Any events it attempts to send after it has been uninstalled will be dropped.
493     *
494     * @param filter The input filter, or null to remove the current filter.
495     */
496    public void setInputFilter(IInputFilter filter) {
497        synchronized (mInputFilterLock) {
498            final IInputFilter oldFilter = mInputFilter;
499            if (oldFilter == filter) {
500                return; // nothing to do
501            }
502
503            if (oldFilter != null) {
504                mInputFilter = null;
505                mInputFilterHost.disconnectLocked();
506                mInputFilterHost = null;
507                try {
508                    oldFilter.uninstall();
509                } catch (RemoteException re) {
510                    /* ignore */
511                }
512            }
513
514            if (filter != null) {
515                mInputFilter = filter;
516                mInputFilterHost = new InputFilterHost();
517                try {
518                    filter.install(mInputFilterHost);
519                } catch (RemoteException re) {
520                    /* ignore */
521                }
522            }
523
524            nativeSetInputFilterEnabled(mPtr, filter != null);
525        }
526    }
527
528    @Override // Binder call
529    public boolean injectInputEvent(InputEvent event, int mode) {
530        return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
531    }
532
533    private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
534        if (event == null) {
535            throw new IllegalArgumentException("event must not be null");
536        }
537        if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
538                && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
539                && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
540            throw new IllegalArgumentException("mode is invalid");
541        }
542
543        final int pid = Binder.getCallingPid();
544        final int uid = Binder.getCallingUid();
545        final long ident = Binder.clearCallingIdentity();
546        final int result;
547        try {
548            result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
549                    INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
550        } finally {
551            Binder.restoreCallingIdentity(ident);
552        }
553        switch (result) {
554            case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
555                Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
556                throw new SecurityException(
557                        "Injecting to another application requires INJECT_EVENTS permission");
558            case INPUT_EVENT_INJECTION_SUCCEEDED:
559                return true;
560            case INPUT_EVENT_INJECTION_TIMED_OUT:
561                Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
562                return false;
563            case INPUT_EVENT_INJECTION_FAILED:
564            default:
565                Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
566                return false;
567        }
568    }
569
570    /**
571     * Gets information about the input device with the specified id.
572     * @param deviceId The device id.
573     * @return The input device or null if not found.
574     */
575    @Override // Binder call
576    public InputDevice getInputDevice(int deviceId) {
577        synchronized (mInputDevicesLock) {
578            final int count = mInputDevices.length;
579            for (int i = 0; i < count; i++) {
580                final InputDevice inputDevice = mInputDevices[i];
581                if (inputDevice.getId() == deviceId) {
582                    return inputDevice;
583                }
584            }
585        }
586        return null;
587    }
588
589    /**
590     * Gets the ids of all input devices in the system.
591     * @return The input device ids.
592     */
593    @Override // Binder call
594    public int[] getInputDeviceIds() {
595        synchronized (mInputDevicesLock) {
596            final int count = mInputDevices.length;
597            int[] ids = new int[count];
598            for (int i = 0; i < count; i++) {
599                ids[i] = mInputDevices[i].getId();
600            }
601            return ids;
602        }
603    }
604
605    /**
606     * Gets all input devices in the system.
607     * @return The array of input devices.
608     */
609    public InputDevice[] getInputDevices() {
610        synchronized (mInputDevicesLock) {
611            return mInputDevices;
612        }
613    }
614
615    @Override // Binder call
616    public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
617        if (listener == null) {
618            throw new IllegalArgumentException("listener must not be null");
619        }
620
621        synchronized (mInputDevicesLock) {
622            int callingPid = Binder.getCallingPid();
623            if (mInputDevicesChangedListeners.get(callingPid) != null) {
624                throw new SecurityException("The calling process has already "
625                        + "registered an InputDevicesChangedListener.");
626            }
627
628            InputDevicesChangedListenerRecord record =
629                    new InputDevicesChangedListenerRecord(callingPid, listener);
630            try {
631                IBinder binder = listener.asBinder();
632                binder.linkToDeath(record, 0);
633            } catch (RemoteException ex) {
634                // give up
635                throw new RuntimeException(ex);
636            }
637
638            mInputDevicesChangedListeners.put(callingPid, record);
639        }
640    }
641
642    private void onInputDevicesChangedListenerDied(int pid) {
643        synchronized (mInputDevicesLock) {
644            mInputDevicesChangedListeners.remove(pid);
645        }
646    }
647
648    // Must be called on handler.
649    private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
650        // Scan for changes.
651        int numFullKeyboardsAdded = 0;
652        mTempInputDevicesChangedListenersToNotify.clear();
653        mTempFullKeyboards.clear();
654        final int numListeners;
655        final int[] deviceIdAndGeneration;
656        synchronized (mInputDevicesLock) {
657            if (!mInputDevicesChangedPending) {
658                return;
659            }
660            mInputDevicesChangedPending = false;
661
662            numListeners = mInputDevicesChangedListeners.size();
663            for (int i = 0; i < numListeners; i++) {
664                mTempInputDevicesChangedListenersToNotify.add(
665                        mInputDevicesChangedListeners.valueAt(i));
666            }
667
668            final int numDevices = mInputDevices.length;
669            deviceIdAndGeneration = new int[numDevices * 2];
670            for (int i = 0; i < numDevices; i++) {
671                final InputDevice inputDevice = mInputDevices[i];
672                deviceIdAndGeneration[i * 2] = inputDevice.getId();
673                deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
674
675                if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
676                    if (!containsInputDeviceWithDescriptor(oldInputDevices,
677                            inputDevice.getDescriptor())) {
678                        mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
679                    } else {
680                        mTempFullKeyboards.add(inputDevice);
681                    }
682                }
683            }
684        }
685
686        // Notify listeners.
687        for (int i = 0; i < numListeners; i++) {
688            mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
689                    deviceIdAndGeneration);
690        }
691        mTempInputDevicesChangedListenersToNotify.clear();
692
693        // Check for missing keyboard layouts.
694        if (mNotificationManager != null) {
695            final int numFullKeyboards = mTempFullKeyboards.size();
696            boolean missingLayoutForExternalKeyboard = false;
697            boolean missingLayoutForExternalKeyboardAdded = false;
698            boolean multipleMissingLayoutsForExternalKeyboardsAdded = false;
699            InputDevice keyboardMissingLayout = null;
700            synchronized (mDataStore) {
701                for (int i = 0; i < numFullKeyboards; i++) {
702                    final InputDevice inputDevice = mTempFullKeyboards.get(i);
703                    final String layout =
704                            getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
705                    if (layout == null) {
706                        missingLayoutForExternalKeyboard = true;
707                        if (i < numFullKeyboardsAdded) {
708                            missingLayoutForExternalKeyboardAdded = true;
709                            if (keyboardMissingLayout == null) {
710                                keyboardMissingLayout = inputDevice;
711                            } else {
712                                multipleMissingLayoutsForExternalKeyboardsAdded = true;
713                            }
714                        }
715                    }
716                }
717            }
718            if (missingLayoutForExternalKeyboard) {
719                if (missingLayoutForExternalKeyboardAdded) {
720                    if (multipleMissingLayoutsForExternalKeyboardsAdded) {
721                        // We have more than one keyboard missing a layout, so drop the
722                        // user at the generic input methods page so they can pick which
723                        // one to set.
724                        showMissingKeyboardLayoutNotification(null);
725                    } else {
726                        showMissingKeyboardLayoutNotification(keyboardMissingLayout);
727                    }
728                }
729            } else if (mKeyboardLayoutNotificationShown) {
730                hideMissingKeyboardLayoutNotification();
731            }
732        }
733        mTempFullKeyboards.clear();
734    }
735
736    @Override // Binder call & native callback
737    public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
738            int surfaceRotation) {
739        if (inputDeviceDescriptor == null) {
740            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
741        }
742
743        synchronized (mDataStore) {
744            return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
745        }
746    }
747
748    @Override // Binder call
749    public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
750            TouchCalibration calibration) {
751        if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
752                "setTouchCalibrationForInputDevice()")) {
753            throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
754        }
755        if (inputDeviceDescriptor == null) {
756            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
757        }
758        if (calibration == null) {
759            throw new IllegalArgumentException("calibration must not be null");
760        }
761        if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
762            throw new IllegalArgumentException("surfaceRotation value out of bounds");
763        }
764
765        synchronized (mDataStore) {
766            try {
767                if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
768                        calibration)) {
769                    nativeReloadCalibration(mPtr);
770                }
771            } finally {
772                mDataStore.saveIfNeeded();
773            }
774        }
775    }
776
777    // Must be called on handler.
778    private void showMissingKeyboardLayoutNotification(InputDevice device) {
779        if (!mKeyboardLayoutNotificationShown) {
780            final Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
781            if (device != null) {
782                intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
783            }
784            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
785                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
786                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
787            final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
788                    intent, 0, null, UserHandle.CURRENT);
789
790            Resources r = mContext.getResources();
791            Notification notification = new Notification.Builder(mContext)
792                    .setContentTitle(r.getString(
793                            R.string.select_keyboard_layout_notification_title))
794                    .setContentText(r.getString(
795                            R.string.select_keyboard_layout_notification_message))
796                    .setContentIntent(keyboardLayoutIntent)
797                    .setSmallIcon(R.drawable.ic_settings_language)
798                    .setPriority(Notification.PRIORITY_LOW)
799                    .setColor(mContext.getResources().getColor(
800                            com.android.internal.R.color.system_notification_accent_color))
801                    .build();
802            mNotificationManager.notifyAsUser(null,
803                    R.string.select_keyboard_layout_notification_title,
804                    notification, UserHandle.ALL);
805            mKeyboardLayoutNotificationShown = true;
806        }
807    }
808
809    // Must be called on handler.
810    private void hideMissingKeyboardLayoutNotification() {
811        if (mKeyboardLayoutNotificationShown) {
812            mKeyboardLayoutNotificationShown = false;
813            mNotificationManager.cancelAsUser(null,
814                    R.string.select_keyboard_layout_notification_title,
815                    UserHandle.ALL);
816        }
817    }
818
819    // Must be called on handler.
820    private void updateKeyboardLayouts() {
821        // Scan all input devices state for keyboard layouts that have been uninstalled.
822        final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
823        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
824            @Override
825            public void visitKeyboardLayout(Resources resources, String descriptor, String label,
826                    String collection, int keyboardLayoutResId, int priority) {
827                availableKeyboardLayouts.add(descriptor);
828            }
829        });
830        synchronized (mDataStore) {
831            try {
832                mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
833            } finally {
834                mDataStore.saveIfNeeded();
835            }
836        }
837
838        // Reload keyboard layouts.
839        reloadKeyboardLayouts();
840    }
841
842    private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
843            String descriptor) {
844        final int numDevices = inputDevices.length;
845        for (int i = 0; i < numDevices; i++) {
846            final InputDevice inputDevice = inputDevices[i];
847            if (inputDevice.getDescriptor().equals(descriptor)) {
848                return true;
849            }
850        }
851        return false;
852    }
853
854    @Override // Binder call
855    public KeyboardLayout[] getKeyboardLayouts() {
856        final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
857        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
858            @Override
859            public void visitKeyboardLayout(Resources resources, String descriptor, String label,
860                    String collection, int keyboardLayoutResId, int priority) {
861                list.add(new KeyboardLayout(descriptor, label, collection, priority));
862            }
863        });
864        return list.toArray(new KeyboardLayout[list.size()]);
865    }
866
867    @Override // Binder call
868    public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
869        if (keyboardLayoutDescriptor == null) {
870            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
871        }
872
873        final KeyboardLayout[] result = new KeyboardLayout[1];
874        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
875            @Override
876            public void visitKeyboardLayout(Resources resources, String descriptor,
877                    String label, String collection, int keyboardLayoutResId, int priority) {
878                result[0] = new KeyboardLayout(descriptor, label, collection, priority);
879            }
880        });
881        if (result[0] == null) {
882            Log.w(TAG, "Could not get keyboard layout with descriptor '"
883                    + keyboardLayoutDescriptor + "'.");
884        }
885        return result[0];
886    }
887
888    private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
889        final PackageManager pm = mContext.getPackageManager();
890        Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
891        for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
892                PackageManager.GET_META_DATA)) {
893            final ActivityInfo activityInfo = resolveInfo.activityInfo;
894            final int priority = resolveInfo.priority;
895            visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
896        }
897    }
898
899    private void visitKeyboardLayout(String keyboardLayoutDescriptor,
900            KeyboardLayoutVisitor visitor) {
901        KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
902        if (d != null) {
903            final PackageManager pm = mContext.getPackageManager();
904            try {
905                ActivityInfo receiver = pm.getReceiverInfo(
906                        new ComponentName(d.packageName, d.receiverName),
907                        PackageManager.GET_META_DATA);
908                visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
909            } catch (NameNotFoundException ex) {
910            }
911        }
912    }
913
914    private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
915            String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
916        Bundle metaData = receiver.metaData;
917        if (metaData == null) {
918            return;
919        }
920
921        int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
922        if (configResId == 0) {
923            Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
924                    + "' on receiver " + receiver.packageName + "/" + receiver.name);
925            return;
926        }
927
928        CharSequence receiverLabel = receiver.loadLabel(pm);
929        String collection = receiverLabel != null ? receiverLabel.toString() : "";
930        int priority;
931        if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
932            priority = requestedPriority;
933        } else {
934            priority = 0;
935        }
936
937        try {
938            Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
939            XmlResourceParser parser = resources.getXml(configResId);
940            try {
941                XmlUtils.beginDocument(parser, "keyboard-layouts");
942
943                for (;;) {
944                    XmlUtils.nextElement(parser);
945                    String element = parser.getName();
946                    if (element == null) {
947                        break;
948                    }
949                    if (element.equals("keyboard-layout")) {
950                        TypedArray a = resources.obtainAttributes(
951                                parser, com.android.internal.R.styleable.KeyboardLayout);
952                        try {
953                            String name = a.getString(
954                                    com.android.internal.R.styleable.KeyboardLayout_name);
955                            String label = a.getString(
956                                    com.android.internal.R.styleable.KeyboardLayout_label);
957                            int keyboardLayoutResId = a.getResourceId(
958                                    com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
959                                    0);
960                            if (name == null || label == null || keyboardLayoutResId == 0) {
961                                Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
962                                        + "attributes in keyboard layout "
963                                        + "resource from receiver "
964                                        + receiver.packageName + "/" + receiver.name);
965                            } else {
966                                String descriptor = KeyboardLayoutDescriptor.format(
967                                        receiver.packageName, receiver.name, name);
968                                if (keyboardName == null || name.equals(keyboardName)) {
969                                    visitor.visitKeyboardLayout(resources, descriptor,
970                                            label, collection, keyboardLayoutResId, priority);
971                                }
972                            }
973                        } finally {
974                            a.recycle();
975                        }
976                    } else {
977                        Log.w(TAG, "Skipping unrecognized element '" + element
978                                + "' in keyboard layout resource from receiver "
979                                + receiver.packageName + "/" + receiver.name);
980                    }
981                }
982            } finally {
983                parser.close();
984            }
985        } catch (Exception ex) {
986            Log.w(TAG, "Could not parse keyboard layout resource from receiver "
987                    + receiver.packageName + "/" + receiver.name, ex);
988        }
989    }
990
991    /**
992     * Builds a layout descriptor for the vendor/product. This returns the
993     * descriptor for ids that aren't useful (such as the default 0, 0).
994     */
995    private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
996        if (identifier == null || identifier.getDescriptor() == null) {
997            throw new IllegalArgumentException("identifier and descriptor must not be null");
998        }
999
1000        if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1001            return identifier.getDescriptor();
1002        }
1003        StringBuilder bob = new StringBuilder();
1004        bob.append("vendor:").append(identifier.getVendorId());
1005        bob.append(",product:").append(identifier.getProductId());
1006        return bob.toString();
1007    }
1008
1009    @Override // Binder call
1010    public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1011
1012        String key = getLayoutDescriptor(identifier);
1013        synchronized (mDataStore) {
1014            String layout = null;
1015            // try loading it using the layout descriptor if we have it
1016            layout = mDataStore.getCurrentKeyboardLayout(key);
1017            if (layout == null && !key.equals(identifier.getDescriptor())) {
1018                // if it doesn't exist fall back to the device descriptor
1019                layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1020            }
1021            if (DEBUG) {
1022                Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1023                        + layout);
1024            }
1025            return layout;
1026        }
1027    }
1028
1029    @Override // Binder call
1030    public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1031            String keyboardLayoutDescriptor) {
1032        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1033                "setCurrentKeyboardLayoutForInputDevice()")) {
1034            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1035        }
1036        if (keyboardLayoutDescriptor == null) {
1037            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1038        }
1039
1040        String key = getLayoutDescriptor(identifier);
1041        synchronized (mDataStore) {
1042            try {
1043                if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1044                    if (DEBUG) {
1045                        Slog.d(TAG, "Saved keyboard layout using " + key);
1046                    }
1047                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1048                }
1049            } finally {
1050                mDataStore.saveIfNeeded();
1051            }
1052        }
1053    }
1054
1055    @Override // Binder call
1056    public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1057        String key = getLayoutDescriptor(identifier);
1058        synchronized (mDataStore) {
1059            String[] layouts = mDataStore.getKeyboardLayouts(key);
1060            if ((layouts == null || layouts.length == 0)
1061                    && !key.equals(identifier.getDescriptor())) {
1062                layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1063            }
1064            return layouts;
1065        }
1066    }
1067
1068    @Override // Binder call
1069    public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1070            String keyboardLayoutDescriptor) {
1071        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1072                "addKeyboardLayoutForInputDevice()")) {
1073            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1074        }
1075        if (keyboardLayoutDescriptor == null) {
1076            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1077        }
1078
1079        String key = getLayoutDescriptor(identifier);
1080        synchronized (mDataStore) {
1081            try {
1082                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1083                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1084                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1085                }
1086                if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
1087                        && !Objects.equal(oldLayout,
1088                                mDataStore.getCurrentKeyboardLayout(key))) {
1089                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1090                }
1091            } finally {
1092                mDataStore.saveIfNeeded();
1093            }
1094        }
1095    }
1096
1097    @Override // Binder call
1098    public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1099            String keyboardLayoutDescriptor) {
1100        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1101                "removeKeyboardLayoutForInputDevice()")) {
1102            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1103        }
1104        if (keyboardLayoutDescriptor == null) {
1105            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1106        }
1107
1108        String key = getLayoutDescriptor(identifier);
1109        synchronized (mDataStore) {
1110            try {
1111                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1112                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1113                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1114                }
1115                boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1116                if (!key.equals(identifier.getDescriptor())) {
1117                    // We need to remove from both places to ensure it is gone
1118                    removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1119                            keyboardLayoutDescriptor);
1120                }
1121                if (removed && !Objects.equal(oldLayout,
1122                                mDataStore.getCurrentKeyboardLayout(key))) {
1123                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1124                }
1125            } finally {
1126                mDataStore.saveIfNeeded();
1127            }
1128        }
1129    }
1130
1131    public void switchKeyboardLayout(int deviceId, int direction) {
1132        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1133    }
1134
1135    // Must be called on handler.
1136    private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1137        final InputDevice device = getInputDevice(deviceId);
1138        if (device != null) {
1139            final boolean changed;
1140            final String keyboardLayoutDescriptor;
1141
1142            String key = getLayoutDescriptor(device.getIdentifier());
1143            synchronized (mDataStore) {
1144                try {
1145                    changed = mDataStore.switchKeyboardLayout(key, direction);
1146                    keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
1147                            key);
1148                } finally {
1149                    mDataStore.saveIfNeeded();
1150                }
1151            }
1152
1153            if (changed) {
1154                if (mSwitchedKeyboardLayoutToast != null) {
1155                    mSwitchedKeyboardLayoutToast.cancel();
1156                    mSwitchedKeyboardLayoutToast = null;
1157                }
1158                if (keyboardLayoutDescriptor != null) {
1159                    KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1160                    if (keyboardLayout != null) {
1161                        mSwitchedKeyboardLayoutToast = Toast.makeText(
1162                                mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1163                        mSwitchedKeyboardLayoutToast.show();
1164                    }
1165                }
1166
1167                reloadKeyboardLayouts();
1168            }
1169        }
1170    }
1171
1172    public void setInputWindows(InputWindowHandle[] windowHandles) {
1173        nativeSetInputWindows(mPtr, windowHandles);
1174    }
1175
1176    public void setFocusedApplication(InputApplicationHandle application) {
1177        nativeSetFocusedApplication(mPtr, application);
1178    }
1179
1180    public void setInputDispatchMode(boolean enabled, boolean frozen) {
1181        nativeSetInputDispatchMode(mPtr, enabled, frozen);
1182    }
1183
1184    public void setSystemUiVisibility(int visibility) {
1185        nativeSetSystemUiVisibility(mPtr, visibility);
1186    }
1187
1188    /**
1189     * Atomically transfers touch focus from one window to another as identified by
1190     * their input channels.  It is possible for multiple windows to have
1191     * touch focus if they support split touch dispatch
1192     * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1193     * method only transfers touch focus of the specified window without affecting
1194     * other windows that may also have touch focus at the same time.
1195     * @param fromChannel The channel of a window that currently has touch focus.
1196     * @param toChannel The channel of the window that should receive touch focus in
1197     * place of the first.
1198     * @return True if the transfer was successful.  False if the window with the
1199     * specified channel did not actually have touch focus at the time of the request.
1200     */
1201    public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1202        if (fromChannel == null) {
1203            throw new IllegalArgumentException("fromChannel must not be null.");
1204        }
1205        if (toChannel == null) {
1206            throw new IllegalArgumentException("toChannel must not be null.");
1207        }
1208        return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
1209    }
1210
1211    @Override // Binder call
1212    public void tryPointerSpeed(int speed) {
1213        if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1214                "tryPointerSpeed()")) {
1215            throw new SecurityException("Requires SET_POINTER_SPEED permission");
1216        }
1217
1218        if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1219            throw new IllegalArgumentException("speed out of range");
1220        }
1221
1222        setPointerSpeedUnchecked(speed);
1223    }
1224
1225    public void updatePointerSpeedFromSettings() {
1226        int speed = getPointerSpeedSetting();
1227        setPointerSpeedUnchecked(speed);
1228    }
1229
1230    private void setPointerSpeedUnchecked(int speed) {
1231        speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1232                InputManager.MAX_POINTER_SPEED);
1233        nativeSetPointerSpeed(mPtr, speed);
1234    }
1235
1236    private void registerPointerSpeedSettingObserver() {
1237        mContext.getContentResolver().registerContentObserver(
1238                Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
1239                new ContentObserver(mHandler) {
1240                    @Override
1241                    public void onChange(boolean selfChange) {
1242                        updatePointerSpeedFromSettings();
1243                    }
1244                }, UserHandle.USER_ALL);
1245    }
1246
1247    private int getPointerSpeedSetting() {
1248        int speed = InputManager.DEFAULT_POINTER_SPEED;
1249        try {
1250            speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1251                    Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
1252        } catch (SettingNotFoundException snfe) {
1253        }
1254        return speed;
1255    }
1256
1257    public void updateShowTouchesFromSettings() {
1258        int setting = getShowTouchesSetting(0);
1259        nativeSetShowTouches(mPtr, setting != 0);
1260    }
1261
1262    private void registerShowTouchesSettingObserver() {
1263        mContext.getContentResolver().registerContentObserver(
1264                Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
1265                new ContentObserver(mHandler) {
1266                    @Override
1267                    public void onChange(boolean selfChange) {
1268                        updateShowTouchesFromSettings();
1269                    }
1270                }, UserHandle.USER_ALL);
1271    }
1272
1273    private int getShowTouchesSetting(int defaultValue) {
1274        int result = defaultValue;
1275        try {
1276            result = Settings.System.getIntForUser(mContext.getContentResolver(),
1277                    Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
1278        } catch (SettingNotFoundException snfe) {
1279        }
1280        return result;
1281    }
1282
1283    // Binder call
1284    @Override
1285    public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1286        if (repeat >= pattern.length) {
1287            throw new ArrayIndexOutOfBoundsException();
1288        }
1289
1290        VibratorToken v;
1291        synchronized (mVibratorLock) {
1292            v = mVibratorTokens.get(token);
1293            if (v == null) {
1294                v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1295                try {
1296                    token.linkToDeath(v, 0);
1297                } catch (RemoteException ex) {
1298                    // give up
1299                    throw new RuntimeException(ex);
1300                }
1301                mVibratorTokens.put(token, v);
1302            }
1303        }
1304
1305        synchronized (v) {
1306            v.mVibrating = true;
1307            nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1308        }
1309    }
1310
1311    // Binder call
1312    @Override
1313    public void cancelVibrate(int deviceId, IBinder token) {
1314        VibratorToken v;
1315        synchronized (mVibratorLock) {
1316            v = mVibratorTokens.get(token);
1317            if (v == null || v.mDeviceId != deviceId) {
1318                return; // nothing to cancel
1319            }
1320        }
1321
1322        cancelVibrateIfNeeded(v);
1323    }
1324
1325    void onVibratorTokenDied(VibratorToken v) {
1326        synchronized (mVibratorLock) {
1327            mVibratorTokens.remove(v.mToken);
1328        }
1329
1330        cancelVibrateIfNeeded(v);
1331    }
1332
1333    private void cancelVibrateIfNeeded(VibratorToken v) {
1334        synchronized (v) {
1335            if (v.mVibrating) {
1336                nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1337                v.mVibrating = false;
1338            }
1339        }
1340    }
1341
1342    @Override
1343    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1344        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
1345                != PackageManager.PERMISSION_GRANTED) {
1346            pw.println("Permission Denial: can't dump InputManager from from pid="
1347                    + Binder.getCallingPid()
1348                    + ", uid=" + Binder.getCallingUid());
1349            return;
1350        }
1351
1352        pw.println("INPUT MANAGER (dumpsys input)\n");
1353        String dumpStr = nativeDump(mPtr);
1354        if (dumpStr != null) {
1355            pw.println(dumpStr);
1356        }
1357    }
1358
1359    private boolean checkCallingPermission(String permission, String func) {
1360        // Quick check: if the calling permission is me, it's all okay.
1361        if (Binder.getCallingPid() == Process.myPid()) {
1362            return true;
1363        }
1364
1365        if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1366            return true;
1367        }
1368        String msg = "Permission Denial: " + func + " from pid="
1369                + Binder.getCallingPid()
1370                + ", uid=" + Binder.getCallingUid()
1371                + " requires " + permission;
1372        Slog.w(TAG, msg);
1373        return false;
1374    }
1375
1376    // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
1377    @Override
1378    public void monitor() {
1379        synchronized (mInputFilterLock) { }
1380        nativeMonitor(mPtr);
1381    }
1382
1383    // Native callback.
1384    private void notifyConfigurationChanged(long whenNanos) {
1385        mWindowManagerCallbacks.notifyConfigurationChanged();
1386    }
1387
1388    // Native callback.
1389    private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1390        synchronized (mInputDevicesLock) {
1391            if (!mInputDevicesChangedPending) {
1392                mInputDevicesChangedPending = true;
1393                mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1394                        mInputDevices).sendToTarget();
1395            }
1396
1397            mInputDevices = inputDevices;
1398        }
1399    }
1400
1401    // Native callback.
1402    private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1403        if (DEBUG) {
1404            Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1405                    + ", mask=" + Integer.toHexString(switchMask));
1406        }
1407
1408        if ((switchMask & SW_LID_BIT) != 0) {
1409            final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
1410            mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
1411        }
1412
1413        if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
1414            final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
1415            mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1416        }
1417
1418        if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1419            mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1420                    switchMask);
1421        }
1422    }
1423
1424    // Native callback.
1425    private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
1426        mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
1427    }
1428
1429    // Native callback.
1430    private long notifyANR(InputApplicationHandle inputApplicationHandle,
1431            InputWindowHandle inputWindowHandle, String reason) {
1432        return mWindowManagerCallbacks.notifyANR(
1433                inputApplicationHandle, inputWindowHandle, reason);
1434    }
1435
1436    // Native callback.
1437    final boolean filterInputEvent(InputEvent event, int policyFlags) {
1438        synchronized (mInputFilterLock) {
1439            if (mInputFilter != null) {
1440                try {
1441                    mInputFilter.filterInputEvent(event, policyFlags);
1442                } catch (RemoteException e) {
1443                    /* ignore */
1444                }
1445                return false;
1446            }
1447        }
1448        event.recycle();
1449        return true;
1450    }
1451
1452    // Native callback.
1453    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1454        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
1455    }
1456
1457    // Native callback.
1458    private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1459        return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
1460                whenNanos, policyFlags);
1461    }
1462
1463    // Native callback.
1464    private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1465            KeyEvent event, int policyFlags) {
1466        return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
1467    }
1468
1469    // Native callback.
1470    private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1471            KeyEvent event, int policyFlags) {
1472        return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
1473    }
1474
1475    // Native callback.
1476    private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1477        return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1478                injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1479    }
1480
1481    // Native callback.
1482    private int getVirtualKeyQuietTimeMillis() {
1483        return mContext.getResources().getInteger(
1484                com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1485    }
1486
1487    // Native callback.
1488    private String[] getExcludedDeviceNames() {
1489        ArrayList<String> names = new ArrayList<String>();
1490
1491        // Read partner-provided list of excluded input devices
1492        XmlPullParser parser = null;
1493        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1494        File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1495        FileReader confreader = null;
1496        try {
1497            confreader = new FileReader(confFile);
1498            parser = Xml.newPullParser();
1499            parser.setInput(confreader);
1500            XmlUtils.beginDocument(parser, "devices");
1501
1502            while (true) {
1503                XmlUtils.nextElement(parser);
1504                if (!"device".equals(parser.getName())) {
1505                    break;
1506                }
1507                String name = parser.getAttributeValue(null, "name");
1508                if (name != null) {
1509                    names.add(name);
1510                }
1511            }
1512        } catch (FileNotFoundException e) {
1513            // It's ok if the file does not exist.
1514        } catch (Exception e) {
1515            Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1516        } finally {
1517            try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1518        }
1519
1520        return names.toArray(new String[names.size()]);
1521    }
1522
1523    // Native callback.
1524    private int getKeyRepeatTimeout() {
1525        return ViewConfiguration.getKeyRepeatTimeout();
1526    }
1527
1528    // Native callback.
1529    private int getKeyRepeatDelay() {
1530        return ViewConfiguration.getKeyRepeatDelay();
1531    }
1532
1533    // Native callback.
1534    private int getHoverTapTimeout() {
1535        return ViewConfiguration.getHoverTapTimeout();
1536    }
1537
1538    // Native callback.
1539    private int getHoverTapSlop() {
1540        return ViewConfiguration.getHoverTapSlop();
1541    }
1542
1543    // Native callback.
1544    private int getDoubleTapTimeout() {
1545        return ViewConfiguration.getDoubleTapTimeout();
1546    }
1547
1548    // Native callback.
1549    private int getLongPressTimeout() {
1550        return ViewConfiguration.getLongPressTimeout();
1551    }
1552
1553    // Native callback.
1554    private int getPointerLayer() {
1555        return mWindowManagerCallbacks.getPointerLayer();
1556    }
1557
1558    // Native callback.
1559    private PointerIcon getPointerIcon() {
1560        return PointerIcon.getDefaultIcon(mContext);
1561    }
1562
1563    // Native callback.
1564    private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
1565        if (!mSystemReady) {
1566            return null;
1567        }
1568
1569        String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
1570        if (keyboardLayoutDescriptor == null) {
1571            return null;
1572        }
1573
1574        final String[] result = new String[2];
1575        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1576            @Override
1577            public void visitKeyboardLayout(Resources resources, String descriptor, String label,
1578                    String collection, int keyboardLayoutResId, int priority) {
1579                try {
1580                    result[0] = descriptor;
1581                    result[1] = Streams.readFully(new InputStreamReader(
1582                            resources.openRawResource(keyboardLayoutResId)));
1583                } catch (IOException ex) {
1584                } catch (NotFoundException ex) {
1585                }
1586            }
1587        });
1588        if (result[0] == null) {
1589            Log.w(TAG, "Could not get keyboard layout with descriptor '"
1590                    + keyboardLayoutDescriptor + "'.");
1591            return null;
1592        }
1593        return result;
1594    }
1595
1596    // Native callback.
1597    private String getDeviceAlias(String uniqueId) {
1598        if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
1599            // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
1600            return null;
1601        }
1602        return null;
1603    }
1604
1605    /**
1606     * Callback interface implemented by the Window Manager.
1607     */
1608    public interface WindowManagerCallbacks {
1609        public void notifyConfigurationChanged();
1610
1611        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1612
1613        public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
1614
1615        public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1616
1617        public long notifyANR(InputApplicationHandle inputApplicationHandle,
1618                InputWindowHandle inputWindowHandle, String reason);
1619
1620        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
1621
1622        public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
1623
1624        public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1625                KeyEvent event, int policyFlags);
1626
1627        public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1628                KeyEvent event, int policyFlags);
1629
1630        public int getPointerLayer();
1631    }
1632
1633    /**
1634     * Callback interface implemented by WiredAccessoryObserver.
1635     */
1636    public interface WiredAccessoryCallbacks {
1637        public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
1638        public void systemReady();
1639    }
1640
1641    /**
1642     * Private handler for the input manager.
1643     */
1644    private final class InputManagerHandler extends Handler {
1645        public InputManagerHandler(Looper looper) {
1646            super(looper, null, true /*async*/);
1647        }
1648
1649        @Override
1650        public void handleMessage(Message msg) {
1651            switch (msg.what) {
1652                case MSG_DELIVER_INPUT_DEVICES_CHANGED:
1653                    deliverInputDevicesChanged((InputDevice[])msg.obj);
1654                    break;
1655                case MSG_SWITCH_KEYBOARD_LAYOUT:
1656                    handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
1657                    break;
1658                case MSG_RELOAD_KEYBOARD_LAYOUTS:
1659                    reloadKeyboardLayouts();
1660                    break;
1661                case MSG_UPDATE_KEYBOARD_LAYOUTS:
1662                    updateKeyboardLayouts();
1663                    break;
1664                case MSG_RELOAD_DEVICE_ALIASES:
1665                    reloadDeviceAliases();
1666                    break;
1667            }
1668        }
1669    }
1670
1671    /**
1672     * Hosting interface for input filters to call back into the input manager.
1673     */
1674    private final class InputFilterHost extends IInputFilterHost.Stub {
1675        private boolean mDisconnected;
1676
1677        public void disconnectLocked() {
1678            mDisconnected = true;
1679        }
1680
1681        @Override
1682        public void sendInputEvent(InputEvent event, int policyFlags) {
1683            if (event == null) {
1684                throw new IllegalArgumentException("event must not be null");
1685            }
1686
1687            synchronized (mInputFilterLock) {
1688                if (!mDisconnected) {
1689                    nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
1690                            InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
1691                            policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1692                }
1693            }
1694        }
1695    }
1696
1697    private static final class KeyboardLayoutDescriptor {
1698        public String packageName;
1699        public String receiverName;
1700        public String keyboardLayoutName;
1701
1702        public static String format(String packageName,
1703                String receiverName, String keyboardName) {
1704            return packageName + "/" + receiverName + "/" + keyboardName;
1705        }
1706
1707        public static KeyboardLayoutDescriptor parse(String descriptor) {
1708            int pos = descriptor.indexOf('/');
1709            if (pos < 0 || pos + 1 == descriptor.length()) {
1710                return null;
1711            }
1712            int pos2 = descriptor.indexOf('/', pos + 1);
1713            if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1714                return null;
1715            }
1716
1717            KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1718            result.packageName = descriptor.substring(0, pos);
1719            result.receiverName = descriptor.substring(pos + 1, pos2);
1720            result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1721            return result;
1722        }
1723    }
1724
1725    private interface KeyboardLayoutVisitor {
1726        void visitKeyboardLayout(Resources resources, String descriptor, String label,
1727                String collection, int keyboardLayoutResId, int priority);
1728    }
1729
1730    private final class InputDevicesChangedListenerRecord implements DeathRecipient {
1731        private final int mPid;
1732        private final IInputDevicesChangedListener mListener;
1733
1734        public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
1735            mPid = pid;
1736            mListener = listener;
1737        }
1738
1739        @Override
1740        public void binderDied() {
1741            if (DEBUG) {
1742                Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
1743            }
1744            onInputDevicesChangedListenerDied(mPid);
1745        }
1746
1747        public void notifyInputDevicesChanged(int[] info) {
1748            try {
1749                mListener.onInputDevicesChanged(info);
1750            } catch (RemoteException ex) {
1751                Slog.w(TAG, "Failed to notify process "
1752                        + mPid + " that input devices changed, assuming it died.", ex);
1753                binderDied();
1754            }
1755        }
1756    }
1757
1758    private final class VibratorToken implements DeathRecipient {
1759        public final int mDeviceId;
1760        public final IBinder mToken;
1761        public final int mTokenValue;
1762
1763        public boolean mVibrating;
1764
1765        public VibratorToken(int deviceId, IBinder token, int tokenValue) {
1766            mDeviceId = deviceId;
1767            mToken = token;
1768            mTokenValue = tokenValue;
1769        }
1770
1771        @Override
1772        public void binderDied() {
1773            if (DEBUG) {
1774                Slog.d(TAG, "Vibrator token died.");
1775            }
1776            onVibratorTokenDied(this);
1777        }
1778    }
1779
1780    private final class LocalService extends InputManagerInternal {
1781        @Override
1782        public void setDisplayViewports(
1783                DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
1784            setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
1785        }
1786
1787        @Override
1788        public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
1789            return injectInputEventInternal(event, displayId, mode);
1790        }
1791
1792        @Override
1793        public void setInteractive(boolean interactive) {
1794            nativeSetInteractive(mPtr, interactive);
1795        }
1796    }
1797}
1798