1 /* 2 * Copyright (C) 2017 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 17 package com.android.systemui.shared.system; 18 19 import static android.view.WindowManager.INPUT_CONSUMER_PIP; 20 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; 21 22 import android.os.Binder; 23 import android.os.IBinder; 24 import android.os.Looper; 25 import android.os.RemoteException; 26 import android.util.Log; 27 import android.view.BatchedInputEventReceiver; 28 import android.view.Choreographer; 29 import android.view.InputChannel; 30 import android.view.InputEvent; 31 import android.view.IWindowManager; 32 import android.view.MotionEvent; 33 import android.view.WindowManagerGlobal; 34 35 import java.io.PrintWriter; 36 37 /** 38 * Manages the input consumer that allows the SystemUI to directly receive touch input. 39 */ 40 public class InputConsumerController { 41 42 private static final String TAG = InputConsumerController.class.getSimpleName(); 43 44 /** 45 * Listener interface for callers to subscribe to touch events. 46 */ 47 public interface TouchListener { onTouchEvent(MotionEvent ev)48 boolean onTouchEvent(MotionEvent ev); 49 } 50 51 /** 52 * Listener interface for callers to learn when this class is registered or unregistered with 53 * window manager 54 */ 55 public interface RegistrationListener { onRegistrationChanged(boolean isRegistered)56 void onRegistrationChanged(boolean isRegistered); 57 } 58 59 /** 60 * Input handler used for the input consumer. Input events are batched and consumed with the 61 * SurfaceFlinger vsync. 62 */ 63 private final class InputEventReceiver extends BatchedInputEventReceiver { 64 InputEventReceiver(InputChannel inputChannel, Looper looper)65 public InputEventReceiver(InputChannel inputChannel, Looper looper) { 66 super(inputChannel, looper, Choreographer.getSfInstance()); 67 } 68 69 @Override onInputEvent(InputEvent event, int displayId)70 public void onInputEvent(InputEvent event, int displayId) { 71 boolean handled = true; 72 try { 73 if (mListener != null && event instanceof MotionEvent) { 74 MotionEvent ev = (MotionEvent) event; 75 handled = mListener.onTouchEvent(ev); 76 } 77 } finally { 78 finishInputEvent(event, handled); 79 } 80 } 81 } 82 83 private final IWindowManager mWindowManager; 84 private final IBinder mToken; 85 private final String mName; 86 87 private InputEventReceiver mInputEventReceiver; 88 private TouchListener mListener; 89 private RegistrationListener mRegistrationListener; 90 91 /** 92 * @param name the name corresponding to the input consumer that is defined in the system. 93 */ InputConsumerController(IWindowManager windowManager, String name)94 public InputConsumerController(IWindowManager windowManager, String name) { 95 mWindowManager = windowManager; 96 mToken = new Binder(); 97 mName = name; 98 } 99 100 /** 101 * @return A controller for the pip input consumer. 102 */ getPipInputConsumer()103 public static InputConsumerController getPipInputConsumer() { 104 return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(), 105 INPUT_CONSUMER_PIP); 106 } 107 108 /** 109 * @return A controller for the recents animation input consumer. 110 */ getRecentsAnimationInputConsumer()111 public static InputConsumerController getRecentsAnimationInputConsumer() { 112 return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(), 113 INPUT_CONSUMER_RECENTS_ANIMATION); 114 } 115 116 /** 117 * Sets the touch listener. 118 */ setTouchListener(TouchListener listener)119 public void setTouchListener(TouchListener listener) { 120 mListener = listener; 121 } 122 123 /** 124 * Sets the registration listener. 125 */ setRegistrationListener(RegistrationListener listener)126 public void setRegistrationListener(RegistrationListener listener) { 127 mRegistrationListener = listener; 128 if (mRegistrationListener != null) { 129 mRegistrationListener.onRegistrationChanged(mInputEventReceiver != null); 130 } 131 } 132 133 /** 134 * Check if the InputConsumer is currently registered with WindowManager 135 * 136 * @return {@code true} if registered, {@code false} if not. 137 */ isRegistered()138 public boolean isRegistered() { 139 return mInputEventReceiver != null; 140 } 141 142 /** 143 * Registers the input consumer. 144 */ registerInputConsumer()145 public void registerInputConsumer() { 146 if (mInputEventReceiver == null) { 147 final InputChannel inputChannel = new InputChannel(); 148 try { 149 mWindowManager.destroyInputConsumer(mName); 150 mWindowManager.createInputConsumer(mToken, mName, inputChannel); 151 } catch (RemoteException e) { 152 Log.e(TAG, "Failed to create input consumer", e); 153 } 154 mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper()); 155 if (mRegistrationListener != null) { 156 mRegistrationListener.onRegistrationChanged(true /* isRegistered */); 157 } 158 } 159 } 160 161 /** 162 * Unregisters the input consumer. 163 */ unregisterInputConsumer()164 public void unregisterInputConsumer() { 165 if (mInputEventReceiver != null) { 166 try { 167 mWindowManager.destroyInputConsumer(mName); 168 } catch (RemoteException e) { 169 Log.e(TAG, "Failed to destroy input consumer", e); 170 } 171 mInputEventReceiver.dispose(); 172 mInputEventReceiver = null; 173 if (mRegistrationListener != null) { 174 mRegistrationListener.onRegistrationChanged(false /* isRegistered */); 175 } 176 } 177 } 178 dump(PrintWriter pw, String prefix)179 public void dump(PrintWriter pw, String prefix) { 180 final String innerPrefix = prefix + " "; 181 pw.println(prefix + TAG); 182 pw.println(innerPrefix + "registered=" + (mInputEventReceiver != null)); 183 } 184 } 185