diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index e3de8106fb1bf..60548162b7186 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1726,6 +1726,16 @@ public interface WindowManager extends ViewManager { */ public CharSequence accessibilityTitle; + /** + * Sets a timeout in milliseconds before which the window will be removed + * by the window manager. Useful for transient notifications like toasts + * so we don't have to rely on client cooperation to ensure the window + * is removed. Must be specified at window creation time. + * + * @hide + */ + public long removeTimeoutMilliseconds = -1; + public LayoutParams() { super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); type = TYPE_APPLICATION; @@ -1847,6 +1857,7 @@ public interface WindowManager extends ViewManager { out.writeInt(needsMenuKey); out.writeInt(accessibilityIdOfAnchor); TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags); + out.writeLong(removeTimeoutMilliseconds); } public static final Parcelable.Creator CREATOR @@ -1900,6 +1911,7 @@ public interface WindowManager extends ViewManager { needsMenuKey = in.readInt(); accessibilityIdOfAnchor = in.readInt(); accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + removeTimeoutMilliseconds = in.readLong(); } @SuppressWarnings({"PointlessBitwiseExpression"}) @@ -2120,6 +2132,9 @@ public interface WindowManager extends ViewManager { changes |= ACCESSIBILITY_TITLE_CHANGED; } + // This can't change, it's only set at window creation time. + removeTimeoutMilliseconds = o.removeTimeoutMilliseconds; + return changes; } diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 207f675945e0d..77626754264f1 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -163,6 +163,7 @@ public class Toast { */ public void setDuration(@Duration int duration) { mDuration = duration; + mTN.mDuration = duration; } /** @@ -342,7 +343,7 @@ public class Toast { }; private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); - final Handler mHandler = new Handler(); + final Handler mHandler = new Handler(); int mGravity; int mX, mY; @@ -352,9 +353,13 @@ public class Toast { View mView; View mNextView; + int mDuration; WindowManager mWM; + static final long SHORT_DURATION_TIMEOUT = 5000; + static final long LONG_DURATION_TIMEOUT = 1000; + TN() { // XXX This should be changed to use a Dialog, with a Theme.Toast // defined that sets up the layout params appropriately. @@ -417,6 +422,8 @@ public class Toast { mParams.verticalMargin = mVerticalMargin; mParams.horizontalMargin = mHorizontalMargin; mParams.packageName = packageName; + mParams.removeTimeoutMilliseconds = mDuration == + Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; if (mView.getParent() != null) { if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9088522dfa8e2..d48ba0531559a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2107,6 +2107,11 @@ public class WindowManagerService extends IWindowManager.Stub if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) { reportNewConfig = true; } + if (attrs.removeTimeoutMilliseconds > 0) { + mH.sendMessageDelayed( + mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win), + attrs.removeTimeoutMilliseconds); + } } if (reportNewConfig) { @@ -7782,8 +7787,8 @@ public class WindowManagerService extends IWindowManager.Stub public static final int NOTIFY_APP_TRANSITION_CANCELLED = 48; public static final int NOTIFY_APP_TRANSITION_FINISHED = 49; public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50; - public static final int UPDATE_ANIMATION_SCALE = 51; + public static final int WINDOW_REMOVE_TIMEOUT = 52; /** * Used to denote that an integer field in a message will not be used. @@ -8396,6 +8401,18 @@ public class WindowManagerService extends IWindowManager.Stub mAmInternal.notifyStartingWindowDrawn(); } break; + case WINDOW_REMOVE_TIMEOUT: { + final WindowState window = (WindowState) msg.obj; + synchronized(mWindowMap) { + // It's counterintuitive that we check that "mWindowRemovalAllowed" + // is false. But in fact if it's true, it means a remove has already + // been requested and we better just not do anything. + if (!window.mRemoved && !window.mWindowRemovalAllowed) { + removeWindowLocked(window); + } + } + } + break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG_WM, "handleMessage: exit");