content: /*
   * Copyright (C) 2011 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.server.wm;
  
  import android.graphics.Point;
  import android.graphics.Rect;
  import android.os.Binder;
  import android.os.IBinder;
  import android.os.Process;
  import android.os.RemoteException;
  import android.os.UserHandle;
  import android.view.InputApplicationHandle;
  import android.view.InputChannel;
  import android.view.InputWindowHandle;
  import android.view.SurfaceControl;
  import android.view.WindowManager;
  
  import java.io.PrintWriter;
  
  class InputConsumerImpl implements IBinder.DeathRecipient {
      final WindowManagerService mService;
      final InputChannel mServerChannel, mClientChannel;
      final InputApplicationHandle mApplicationHandle;
      final InputWindowHandle mWindowHandle;
  
      final IBinder mToken;
      final String mName;
      final int mClientPid;
      final UserHandle mClientUser;
  
      final SurfaceControl mInputSurface;
      Rect mTmpClipRect = new Rect();
      private final Rect mTmpRect = new Rect();
      private final Point mOldPosition = new Point();
      private final Rect mOldWindowCrop = new Rect();
  
      InputConsumerImpl(WindowManagerService service, IBinder token, String name,
              InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId) {
          mService = service;
          mToken = token;
          mName = name;
          mClientPid = clientPid;
          mClientUser = clientUser;
  
          InputChannel[] channels = InputChannel.openInputChannelPair(name);
          mServerChannel = channels[0];
          if (inputChannel != null) {
              channels[1].transferTo(inputChannel);
              channels[1].dispose();
              mClientChannel = inputChannel;
          } else {
              mClientChannel = channels[1];
          }
          mService.mInputManager.registerInputChannel(mServerChannel, null);
  
          mApplicationHandle = new InputApplicationHandle(new Binder());
          mApplicationHandle.name = name;
          mApplicationHandle.dispatchingTimeoutNanos =
                  WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
  
          mWindowHandle = new InputWindowHandle(mApplicationHandle, null, displayId);
          mWindowHandle.name = name;
          mWindowHandle.token = mServerChannel.getToken();
          mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
          mWindowHandle.layer = getLayerLw(mWindowHandle.layoutParamsType);
          mWindowHandle.layoutParamsFlags = 0;
          mWindowHandle.dispatchingTimeoutNanos =
                  WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
          mWindowHandle.visible = true;
          mWindowHandle.canReceiveKeys = false;
          mWindowHandle.hasFocus = false;
          mWindowHandle.hasWallpaper = false;
          mWindowHandle.paused = false;
          mWindowHandle.ownerPid = Process.myPid();
          mWindowHandle.ownerUid = Process.myUid();
          mWindowHandle.inputFeatures = 0;
          mWindowHandle.scaleFactor = 1.0f;
  
          mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId)
                  .getSession()).setContainerLayer().setName("Input Consumer " + name)
                  .build();
      }
  
      void linkToDeathRecipient() {
          if (mToken == null) {
              return;
          }
  
          try {
              mToken.linkToDeath(this, 0);
          } catch (RemoteException e) {
              // Client died, do nothing
          }
      }
  
      void unlinkFromDeathRecipient() {
          if (mToken == null) {
              return;
          }
  
          mToken.unlinkToDeath(this, 0);
      }
  
      void layout(SurfaceControl.Transaction t, int dw, int dh) {
          mTmpRect.set(0, 0, dw, dh);
          layout(t, mTmpRect);
      }
  
      void layout(SurfaceControl.Transaction t, Rect r) {
          mTmpClipRect.set(0, 0, r.width(), r.height());
  
          if (mOldPosition.equals(r.left, r.top) && mOldWindowCrop.equals(mTmpClipRect)) {
              return;
          }
  
          t.setPosition(mInputSurface, r.left, r.top);
          t.setWindowCrop(mInputSurface, mTmpClipRect);
  
          mOldPosition.set(r.left, r.top);
          mOldWindowCrop.set(mTmpClipRect);
      }
  
      void hide(SurfaceControl.Transaction t) {
          t.hide(mInputSurface);
      }
  
      void show(SurfaceControl.Transaction t, WindowState w) {
          t.show(mInputSurface);
          t.setInputWindowInfo(mInputSurface, mWindowHandle);
          t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1);
      }
  
      void show(SurfaceControl.Transaction t, int layer) {
          t.show(mInputSurface);
          t.setInputWindowInfo(mInputSurface, mWindowHandle);
          t.setLayer(mInputSurface, layer);
      }
  
      private int getLayerLw(int windowType) {
          return mService.mPolicy.getWindowLayerFromTypeLw(windowType)
                  * WindowManagerService.TYPE_LAYER_MULTIPLIER
                  + WindowManagerService.TYPE_LAYER_OFFSET;
      }
  
      void disposeChannelsLw() {
          mService.mInputManager.unregisterInputChannel(mServerChannel);
          mClientChannel.dispose();
          mServerChannel.dispose();
          unlinkFromDeathRecipient();
      }
  
      @Override
      public void binderDied() {
          synchronized (mService.getWindowManagerLock()) {
              // Clean up the input consumer
              final InputMonitor inputMonitor =
                      mService.mRoot.getDisplayContent(mWindowHandle.displayId).getInputMonitor();
              inputMonitor.destroyInputConsumer(mName);
              unlinkFromDeathRecipient();
          }
      }
  
      void dump(PrintWriter pw, String name, String prefix) {
          pw.println(prefix + "  name=" + name + " pid=" + mClientPid + " user=" + mClientUser);
      }
  }
  