blob: 1d95c44c8b15bb42c6e3d89f46ba4c2504700ba4 [file] [log] [blame]
Dianne Hackborn6e1eb762011-02-17 16:07:28 -08001/*
2 * Copyright (C) 2011 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.wm;
18
Dianne Hackborne3f23a32013-03-01 13:25:35 -080019import android.view.IWindowId;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080020import com.android.internal.view.IInputContext;
21import com.android.internal.view.IInputMethodClient;
22import com.android.internal.view.IInputMethodManager;
23import com.android.server.wm.WindowManagerService.H;
24
25import android.content.ClipData;
26import android.content.Context;
27import android.content.res.Configuration;
28import android.graphics.Rect;
29import android.graphics.Region;
30import android.os.Binder;
31import android.os.Bundle;
32import android.os.IBinder;
33import android.os.Parcel;
Dianne Hackborn5fe7e2a2012-10-04 11:58:16 -070034import android.os.Process;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080035import android.os.RemoteException;
36import android.os.ServiceManager;
Dianne Hackborn5fe7e2a2012-10-04 11:58:16 -070037import android.os.UserHandle;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080038import android.util.Slog;
Craig Mautner6881a102012-07-27 13:04:51 -070039import android.view.Display;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080040import android.view.IWindow;
41import android.view.IWindowSession;
42import android.view.InputChannel;
43import android.view.Surface;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080044import android.view.SurfaceControl;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080045import android.view.SurfaceSession;
46import android.view.WindowManager;
47
48import java.io.PrintWriter;
49
50/**
51 * This class represents an active client session. There is generally one
52 * Session object per process that is interacting with the window manager.
53 */
54final class Session extends IWindowSession.Stub
55 implements IBinder.DeathRecipient {
56 final WindowManagerService mService;
57 final IInputMethodClient mClient;
58 final IInputContext mInputContext;
59 final int mUid;
60 final int mPid;
61 final String mStringName;
62 SurfaceSession mSurfaceSession;
63 int mNumWindow = 0;
64 boolean mClientDead = false;
65
66 public Session(WindowManagerService service, IInputMethodClient client,
67 IInputContext inputContext) {
68 mService = service;
69 mClient = client;
70 mInputContext = inputContext;
71 mUid = Binder.getCallingUid();
72 mPid = Binder.getCallingPid();
73 StringBuilder sb = new StringBuilder();
74 sb.append("Session{");
75 sb.append(Integer.toHexString(System.identityHashCode(this)));
Dianne Hackborn5fe7e2a2012-10-04 11:58:16 -070076 sb.append(" ");
77 sb.append(mPid);
78 if (mUid < Process.FIRST_APPLICATION_UID) {
79 sb.append(":");
80 sb.append(mUid);
81 } else {
82 sb.append(":u");
83 sb.append(UserHandle.getUserId(mUid));
84 sb.append('a');
85 sb.append(UserHandle.getAppId(mUid));
86 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080087 sb.append("}");
88 mStringName = sb.toString();
89
90 synchronized (mService.mWindowMap) {
91 if (mService.mInputMethodManager == null && mService.mHaveInputMethods) {
92 IBinder b = ServiceManager.getService(
93 Context.INPUT_METHOD_SERVICE);
94 mService.mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
95 }
96 }
97 long ident = Binder.clearCallingIdentity();
98 try {
99 // Note: it is safe to call in to the input method manager
100 // here because we are not holding our lock.
101 if (mService.mInputMethodManager != null) {
102 mService.mInputMethodManager.addClient(client, inputContext,
103 mUid, mPid);
104 } else {
105 client.setUsingInputMethod(false);
106 }
107 client.asBinder().linkToDeath(this, 0);
108 } catch (RemoteException e) {
109 // The caller has died, so we can just forget about this.
110 try {
111 if (mService.mInputMethodManager != null) {
112 mService.mInputMethodManager.removeClient(client);
113 }
114 } catch (RemoteException ee) {
115 }
116 } finally {
117 Binder.restoreCallingIdentity(ident);
118 }
119 }
120
121 @Override
122 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
123 throws RemoteException {
124 try {
125 return super.onTransact(code, data, reply, flags);
126 } catch (RuntimeException e) {
127 // Log all 'real' exceptions thrown to the caller
128 if (!(e instanceof SecurityException)) {
129 Slog.e(WindowManagerService.TAG, "Window Session Crash", e);
130 }
131 throw e;
132 }
133 }
134
135 public void binderDied() {
136 // Note: it is safe to call in to the input method manager
137 // here because we are not holding our lock.
138 try {
139 if (mService.mInputMethodManager != null) {
140 mService.mInputMethodManager.removeClient(mClient);
141 }
142 } catch (RemoteException e) {
143 }
144 synchronized(mService.mWindowMap) {
145 mClient.asBinder().unlinkToDeath(this, 0);
146 mClientDead = true;
147 killSessionLocked();
148 }
149 }
150
Craig Mautner6881a102012-07-27 13:04:51 -0700151 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700152 public int add(IWindow window, int seq, WindowManager.LayoutParams attrs,
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800153 int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
Craig Mautner6881a102012-07-27 13:04:51 -0700154 return addToDisplay(window, seq, attrs, viewVisibility, Display.DEFAULT_DISPLAY,
155 outContentInsets, outInputChannel);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800156 }
Craig Mautner6881a102012-07-27 13:04:51 -0700157
158 @Override
159 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
160 int viewVisibility, int displayId, Rect outContentInsets,
161 InputChannel outInputChannel) {
162 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
163 outContentInsets, outInputChannel);
164 }
165
166 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700167 public int addWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800168 int viewVisibility, Rect outContentInsets) {
Craig Mautner6881a102012-07-27 13:04:51 -0700169 return addToDisplayWithoutInputChannel(window, seq, attrs, viewVisibility,
170 Display.DEFAULT_DISPLAY, outContentInsets);
171 }
172
173 @Override
174 public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
175 int viewVisibility, int displayId, Rect outContentInsets) {
176 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
177 outContentInsets, null);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800178 }
179
180 public void remove(IWindow window) {
181 mService.removeWindow(this, window);
182 }
183
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700184 public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800185 int requestedWidth, int requestedHeight, int viewFlags,
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800186 int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800187 Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
Dianne Hackbornb961cd22011-06-21 12:13:37 -0700188 if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from "
189 + Binder.getCallingPid());
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700190 int res = mService.relayoutWindow(this, window, seq, attrs,
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800191 requestedWidth, requestedHeight, viewFlags, flags,
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800192 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
Dianne Hackborn5c58de32012-04-28 19:52:37 -0700193 outConfig, outSurface);
Dianne Hackbornb961cd22011-06-21 12:13:37 -0700194 if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to "
195 + Binder.getCallingPid());
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800196 return res;
197 }
198
Dianne Hackborn6d05fd32011-11-19 14:36:15 -0800199 public void performDeferredDestroy(IWindow window) {
200 mService.performDeferredDestroyWindow(this, window);
201 }
202
Dianne Hackborn64825172011-03-02 21:32:58 -0800203 public boolean outOfMemory(IWindow window) {
204 return mService.outOfMemoryWindow(this, window);
205 }
206
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800207 public void setTransparentRegion(IWindow window, Region region) {
208 mService.setTransparentRegionWindow(this, window, region);
209 }
210
211 public void setInsets(IWindow window, int touchableInsets,
212 Rect contentInsets, Rect visibleInsets, Region touchableArea) {
213 mService.setInsetsWindow(this, window, touchableInsets, contentInsets,
214 visibleInsets, touchableArea);
215 }
216
217 public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
218 mService.getWindowDisplayFrame(this, window, outDisplayFrame);
219 }
220
221 public void finishDrawing(IWindow window) {
222 if (WindowManagerService.localLOGV) Slog.v(
223 WindowManagerService.TAG, "IWindow finishDrawing called for " + window);
224 mService.finishDrawingWindow(this, window);
225 }
226
227 public void setInTouchMode(boolean mode) {
228 synchronized(mService.mWindowMap) {
229 mService.mInTouchMode = mode;
230 }
231 }
232
233 public boolean getInTouchMode() {
234 synchronized(mService.mWindowMap) {
235 return mService.mInTouchMode;
236 }
237 }
238
239 public boolean performHapticFeedback(IWindow window, int effectId,
240 boolean always) {
241 synchronized(mService.mWindowMap) {
242 long ident = Binder.clearCallingIdentity();
243 try {
244 return mService.mPolicy.performHapticFeedbackLw(
245 mService.windowForClientLocked(this, window, true),
246 effectId, always);
247 } finally {
248 Binder.restoreCallingIdentity(ident);
249 }
250 }
251 }
252
253 /* Drag/drop */
254 public IBinder prepareDrag(IWindow window, int flags,
255 int width, int height, Surface outSurface) {
256 return mService.prepareDragSurface(window, mSurfaceSession, flags,
257 width, height, outSurface);
258 }
259
260 public boolean performDrag(IWindow window, IBinder dragToken,
261 float touchX, float touchY, float thumbCenterX, float thumbCenterY,
262 ClipData data) {
263 if (WindowManagerService.DEBUG_DRAG) {
264 Slog.d(WindowManagerService.TAG, "perform drag: win=" + window + " data=" + data);
265 }
266
267 synchronized (mService.mWindowMap) {
268 if (mService.mDragState == null) {
269 Slog.w(WindowManagerService.TAG, "No drag prepared");
270 throw new IllegalStateException("performDrag() without prepareDrag()");
271 }
272
273 if (dragToken != mService.mDragState.mToken) {
274 Slog.w(WindowManagerService.TAG, "Performing mismatched drag");
275 throw new IllegalStateException("performDrag() does not match prepareDrag()");
276 }
277
278 WindowState callingWin = mService.windowForClientLocked(null, window, false);
279 if (callingWin == null) {
280 Slog.w(WindowManagerService.TAG, "Bad requesting window " + window);
281 return false; // !!! TODO: throw here?
282 }
283
284 // !!! TODO: if input is not still focused on the initiating window, fail
285 // the drag initiation (e.g. an alarm window popped up just as the application
286 // called performDrag()
287
288 mService.mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder());
289
290 // !!! TODO: extract the current touch (x, y) in screen coordinates. That
291 // will let us eliminate the (touchX,touchY) parameters from the API.
292
293 // !!! FIXME: put all this heavy stuff onto the mH looper, as well as
294 // the actual drag event dispatch stuff in the dragstate
295
Jeff Brown14a9f2b2012-09-24 14:36:44 -0700296 Display display = callingWin.mDisplayContent.getDisplay();
297 mService.mDragState.register(display);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800298 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
299 if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
300 mService.mDragState.mServerChannel)) {
301 Slog.e(WindowManagerService.TAG, "Unable to transfer touch focus");
302 mService.mDragState.unregister();
303 mService.mDragState = null;
304 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
305 return false;
306 }
307
308 mService.mDragState.mData = data;
309 mService.mDragState.mCurrentX = touchX;
310 mService.mDragState.mCurrentY = touchY;
311 mService.mDragState.broadcastDragStartedLw(touchX, touchY);
312
313 // remember the thumb offsets for later
314 mService.mDragState.mThumbOffsetX = thumbCenterX;
315 mService.mDragState.mThumbOffsetY = thumbCenterY;
316
317 // Make the surface visible at the proper location
Mathias Agopian29479eb2013-02-14 14:36:04 -0800318 final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl;
Dianne Hackborn36991742011-10-11 21:35:26 -0700319 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(
320 WindowManagerService.TAG, ">>> OPEN TRANSACTION performDrag");
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800321 SurfaceControl.openTransaction();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800322 try {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800323 surfaceControl.setPosition(touchX - thumbCenterX,
Dianne Hackbornd040edb2011-08-31 12:47:58 -0700324 touchY - thumbCenterY);
Mathias Agopian29479eb2013-02-14 14:36:04 -0800325 surfaceControl.setAlpha(.7071f);
326 surfaceControl.setLayer(mService.mDragState.getDragLayerLw());
327 surfaceControl.setLayerStack(display.getLayerStack());
328 surfaceControl.show();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800329 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800330 SurfaceControl.closeTransaction();
Dianne Hackborn36991742011-10-11 21:35:26 -0700331 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(
332 WindowManagerService.TAG, "<<< CLOSE TRANSACTION performDrag");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800333 }
334 }
335
336 return true; // success!
337 }
338
339 public void reportDropResult(IWindow window, boolean consumed) {
340 IBinder token = window.asBinder();
341 if (WindowManagerService.DEBUG_DRAG) {
342 Slog.d(WindowManagerService.TAG, "Drop result=" + consumed + " reported by " + token);
343 }
344
345 synchronized (mService.mWindowMap) {
346 long ident = Binder.clearCallingIdentity();
347 try {
Christopher Tate05e9c652011-10-20 12:34:36 -0700348 if (mService.mDragState == null) {
349 // Most likely the drop recipient ANRed and we ended the drag
350 // out from under it. Log the issue and move on.
351 Slog.w(WindowManagerService.TAG, "Drop result given but no drag in progress");
352 return;
353 }
354
355 if (mService.mDragState.mToken != token) {
356 // We're in a drag, but the wrong window has responded.
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800357 Slog.w(WindowManagerService.TAG, "Invalid drop-result claim by " + window);
358 throw new IllegalStateException("reportDropResult() by non-recipient");
359 }
360
361 // The right window has responded, even if it's no longer around,
362 // so be sure to halt the timeout even if the later WindowState
363 // lookup fails.
364 mService.mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder());
365 WindowState callingWin = mService.windowForClientLocked(null, window, false);
366 if (callingWin == null) {
367 Slog.w(WindowManagerService.TAG, "Bad result-reporting window " + window);
368 return; // !!! TODO: throw here?
369 }
370
371 mService.mDragState.mDragResult = consumed;
372 mService.mDragState.endDragLw();
373 } finally {
374 Binder.restoreCallingIdentity(ident);
375 }
376 }
377 }
378
379 public void dragRecipientEntered(IWindow window) {
380 if (WindowManagerService.DEBUG_DRAG) {
381 Slog.d(WindowManagerService.TAG, "Drag into new candidate view @ " + window.asBinder());
382 }
383 }
384
385 public void dragRecipientExited(IWindow window) {
386 if (WindowManagerService.DEBUG_DRAG) {
387 Slog.d(WindowManagerService.TAG, "Drag from old candidate view @ " + window.asBinder());
388 }
389 }
390
391 public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) {
392 synchronized(mService.mWindowMap) {
393 long ident = Binder.clearCallingIdentity();
394 try {
395 mService.setWindowWallpaperPositionLocked(
396 mService.windowForClientLocked(this, window, true),
397 x, y, xStep, yStep);
398 } finally {
399 Binder.restoreCallingIdentity(ident);
400 }
401 }
402 }
403
404 public void wallpaperOffsetsComplete(IBinder window) {
405 mService.wallpaperOffsetsComplete(window);
406 }
407
408 public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
409 int z, Bundle extras, boolean sync) {
410 synchronized(mService.mWindowMap) {
411 long ident = Binder.clearCallingIdentity();
412 try {
413 return mService.sendWindowWallpaperCommandLocked(
414 mService.windowForClientLocked(this, window, true),
415 action, x, y, z, extras, sync);
416 } finally {
417 Binder.restoreCallingIdentity(ident);
418 }
419 }
420 }
421
422 public void wallpaperCommandComplete(IBinder window, Bundle result) {
423 mService.wallpaperCommandComplete(window, result);
424 }
425
Dianne Hackborna4b7f2f2012-05-21 11:28:41 -0700426 public void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
427 float dsdx, float dtdx, float dsdy, float dtdy) {
428 synchronized(mService.mWindowMap) {
429 long ident = Binder.clearCallingIdentity();
430 try {
431 mService.setUniverseTransformLocked(
432 mService.windowForClientLocked(this, window, true),
433 alpha, offx, offy, dsdx, dtdx, dsdy, dtdy);
434 } finally {
435 Binder.restoreCallingIdentity(ident);
436 }
437 }
438 }
439
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -0700440 public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
441 synchronized(mService.mWindowMap) {
442 final long identity = Binder.clearCallingIdentity();
443 try {
444 mService.onRectangleOnScreenRequested(token, rectangle, immediate);
445 } finally {
446 Binder.restoreCallingIdentity(identity);
447 }
448 }
449 }
450
Dianne Hackborne3f23a32013-03-01 13:25:35 -0800451 public IWindowId getWindowId(IBinder window) {
452 return mService.getWindowId(window);
453 }
454
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800455 void windowAddedLocked() {
456 if (mSurfaceSession == null) {
457 if (WindowManagerService.localLOGV) Slog.v(
458 WindowManagerService.TAG, "First window added to " + this + ", creating SurfaceSession");
459 mSurfaceSession = new SurfaceSession();
460 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
461 WindowManagerService.TAG, " NEW SURFACE SESSION " + mSurfaceSession);
462 mService.mSessions.add(this);
463 }
464 mNumWindow++;
465 }
466
467 void windowRemovedLocked() {
468 mNumWindow--;
469 killSessionLocked();
470 }
471
472 void killSessionLocked() {
473 if (mNumWindow <= 0 && mClientDead) {
474 mService.mSessions.remove(this);
475 if (mSurfaceSession != null) {
476 if (WindowManagerService.localLOGV) Slog.v(
477 WindowManagerService.TAG, "Last window removed from " + this
478 + ", destroying " + mSurfaceSession);
479 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
480 WindowManagerService.TAG, " KILL SURFACE SESSION " + mSurfaceSession);
481 try {
482 mSurfaceSession.kill();
483 } catch (Exception e) {
484 Slog.w(WindowManagerService.TAG, "Exception thrown when killing surface session "
485 + mSurfaceSession + " in session " + this
486 + ": " + e.toString());
487 }
488 mSurfaceSession = null;
489 }
490 }
491 }
492
493 void dump(PrintWriter pw, String prefix) {
494 pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
495 pw.print(" mClientDead="); pw.print(mClientDead);
496 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
497 }
498
499 @Override
500 public String toString() {
501 return mStringName;
502 }
503}