• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 package android.car.input;
17 
18 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DEPRECATED_CODE;
19 
20 import android.annotation.CallSuper;
21 import android.annotation.MainThread;
22 import android.annotation.SystemApi;
23 import android.app.Service;
24 import android.car.Car;
25 import android.car.CarLibLog;
26 import android.car.annotation.AddedInOrBefore;
27 import android.content.Intent;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.Message;
32 import android.os.Parcel;
33 import android.os.Parcelable;
34 import android.os.RemoteException;
35 import android.util.Log;
36 import android.view.KeyEvent;
37 
38 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
39 
40 import java.io.FileDescriptor;
41 import java.io.PrintWriter;
42 import java.lang.ref.WeakReference;
43 
44 /**
45  * A service that is used for handling of input events.
46  *
47  * <p>To extend this class, you must declare the service in your manifest file with
48  * the {@code android.car.permission.BIND_CAR_INPUT_SERVICE} permission
49  * <pre>
50  * &lt;service android:name=".MyCarInputService"
51  *          android:permission="android.car.permission.BIND_CAR_INPUT_SERVICE">
52  * &lt;/service></pre>
53  * <p>Also, you will need to register this service in the following configuration file:
54  * {@code packages/services/Car/service/res/values/config.xml}
55  *
56  * @deprecated No longer needed after the new Car Input API was introduced (see
57  *         {@link CarInputManager} for more details).
58  *
59  * @removed
60  *
61  * @hide
62  */
63 @SystemApi
64 @Deprecated
65 @ExcludeFromCodeCoverageGeneratedReport(reason = DEPRECATED_CODE)
66 public abstract class CarInputHandlingService extends Service {
67     private static final String TAG = CarLibLog.TAG_INPUT;
68     private static final boolean DBG = false;
69 
70     @AddedInOrBefore(majorVersion = 33)
71     public static final String INPUT_CALLBACK_BINDER_KEY = "callback_binder";
72     @AddedInOrBefore(majorVersion = 33)
73     public static final int INPUT_CALLBACK_BINDER_CODE = IBinder.FIRST_CALL_TRANSACTION;
74 
75     private final InputFilter[] mHandledKeys;
76 
77     private InputBinder mInputBinder;
78 
CarInputHandlingService(InputFilter[] handledKeys)79     protected CarInputHandlingService(InputFilter[] handledKeys) {
80         if (handledKeys == null) {
81             throw new IllegalArgumentException("handledKeys is null");
82         }
83 
84         mHandledKeys = new InputFilter[handledKeys.length];
85         System.arraycopy(handledKeys, 0, mHandledKeys, 0, handledKeys.length);
86     }
87 
88     @Override
89     @CallSuper
90     @AddedInOrBefore(majorVersion = 33)
onBind(Intent intent)91     public IBinder onBind(Intent intent) {
92         if (DBG) {
93             Log.d(TAG, "onBind, intent: " + intent);
94         }
95 
96         doCallbackIfPossible(intent.getExtras());
97 
98         if (mInputBinder == null) {
99             mInputBinder = new InputBinder();
100         }
101 
102         return mInputBinder;
103     }
104 
doCallbackIfPossible(Bundle extras)105     private void doCallbackIfPossible(Bundle extras) {
106         if (extras == null) {
107             Log.i(TAG, "doCallbackIfPossible: extras are null");
108             return;
109         }
110         IBinder callbackBinder = extras.getBinder(INPUT_CALLBACK_BINDER_KEY);
111         if (callbackBinder == null) {
112             Log.i(TAG, "doCallbackIfPossible: callback IBinder is null");
113             return;
114         }
115         Parcel dataIn = Parcel.obtain();
116         try {
117             dataIn.writeTypedArray(mHandledKeys, 0);
118             callbackBinder.transact(INPUT_CALLBACK_BINDER_CODE, dataIn, null, IBinder.FLAG_ONEWAY);
119         } catch (RemoteException e) {
120             Car.handleRemoteExceptionFromCarService(this, e);
121         } finally {
122             dataIn.recycle();
123         }
124     }
125 
126     /**
127      * Called when key event has been received.
128      */
129     @MainThread
130     @AddedInOrBefore(majorVersion = 33)
onKeyEvent(KeyEvent keyEvent, int targetDisplay)131     protected abstract void onKeyEvent(KeyEvent keyEvent, int targetDisplay);
132 
133     @Override
134     @AddedInOrBefore(majorVersion = 33)
dump(FileDescriptor fd, PrintWriter writer, String[] args)135     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
136         writer.println("**" + getClass().getSimpleName() + "**");
137         writer.println("input binder: " + mInputBinder);
138     }
139 
140     private class InputBinder extends ICarInputListener.Stub {
141         private final EventHandler mEventHandler;
142 
InputBinder()143         InputBinder() {
144             mEventHandler = new EventHandler(CarInputHandlingService.this);
145         }
146 
147         @Override
onKeyEvent(KeyEvent keyEvent, int targetDisplay)148         public void onKeyEvent(KeyEvent keyEvent, int targetDisplay) throws RemoteException {
149             mEventHandler.doKeyEvent(keyEvent, targetDisplay);
150         }
151     }
152 
153     private static class EventHandler extends Handler {
154         private static final int KEY_EVENT = 0;
155         private final WeakReference<CarInputHandlingService> mRefService;
156 
EventHandler(CarInputHandlingService service)157         EventHandler(CarInputHandlingService service) {
158             mRefService = new WeakReference<>(service);
159         }
160 
161         @Override
handleMessage(Message msg)162         public void handleMessage(Message msg) {
163             CarInputHandlingService service = mRefService.get();
164             if (service == null) {
165                 return;
166             }
167 
168             if (msg.what == KEY_EVENT) {
169                 service.onKeyEvent((KeyEvent) msg.obj, msg.arg1);
170             } else {
171                 throw new IllegalArgumentException("Unexpected message: " + msg);
172             }
173         }
174 
doKeyEvent(KeyEvent event, int targetDisplay)175         void doKeyEvent(KeyEvent event, int targetDisplay) {
176             sendMessage(obtainMessage(KEY_EVENT, targetDisplay, 0, event));
177         }
178     }
179 
180     /**
181      * Filter for input events that are handled by custom service.
182      */
183     public static final class InputFilter implements Parcelable {
184         @AddedInOrBefore(majorVersion = 33)
185         public final int mKeyCode;
186         @AddedInOrBefore(majorVersion = 33)
187         public final int mTargetDisplay;
188 
InputFilter(int keyCode, int targetDisplay)189         public InputFilter(int keyCode, int targetDisplay) {
190             mKeyCode = keyCode;
191             mTargetDisplay = targetDisplay;
192         }
193 
194         // Parcelling part
InputFilter(Parcel in)195         InputFilter(Parcel in) {
196             mKeyCode = in.readInt();
197             mTargetDisplay = in.readInt();
198         }
199 
200         @Override
201         @AddedInOrBefore(majorVersion = 33)
describeContents()202         public int describeContents() {
203             return 0;
204         }
205 
206         @Override
207         @AddedInOrBefore(majorVersion = 33)
writeToParcel(Parcel dest, int flags)208         public void writeToParcel(Parcel dest, int flags) {
209             dest.writeInt(mKeyCode);
210             dest.writeInt(mTargetDisplay);
211         }
212 
213         @AddedInOrBefore(majorVersion = 33)
214         public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
215             public InputFilter createFromParcel(Parcel in) {
216                 return new InputFilter(in);
217             }
218 
219             public InputFilter[] newArray(int size) {
220                 return new InputFilter[size];
221             }
222         };
223     }
224 }
225