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