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