Merge "Prevent apps to overlay other apps via toast windows" into nyc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
cbfd373d72
@@ -19,7 +19,7 @@ package android.app;
|
|||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
oneway interface ITransientNotification {
|
oneway interface ITransientNotification {
|
||||||
void show();
|
void show(IBinder windowToken);
|
||||||
void hide();
|
void hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ public class SurfaceView extends View {
|
|||||||
mSession = getWindowSession();
|
mSession = getWindowSession();
|
||||||
mLayout.token = getWindowToken();
|
mLayout.token = getWindowToken();
|
||||||
mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
|
mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
|
||||||
|
mLayout.packageName = mContext.getOpPackageName();
|
||||||
mViewVisibility = getVisibility() == VISIBLE;
|
mViewVisibility = getVisibility() == VISIBLE;
|
||||||
|
|
||||||
if (!mGlobalListenersAdded) {
|
if (!mGlobalListenersAdded) {
|
||||||
|
|||||||
@@ -1752,14 +1752,18 @@ public interface WindowManager extends ViewManager {
|
|||||||
public CharSequence accessibilityTitle;
|
public CharSequence accessibilityTitle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a timeout in milliseconds before which the window will be removed
|
* Sets a timeout in milliseconds before which the window will be hidden
|
||||||
* by the window manager. Useful for transient notifications like toasts
|
* by the window manager. Useful for transient notifications like toasts
|
||||||
* so we don't have to rely on client cooperation to ensure the window
|
* so we don't have to rely on client cooperation to ensure the window
|
||||||
* is removed. Must be specified at window creation time.
|
* is hidden. Must be specified at window creation time. Note that apps
|
||||||
|
* are not prepared to handle their windows being removed without their
|
||||||
|
* explicit request and may try to interact with the removed window
|
||||||
|
* resulting in undefined behavior and crashes. Therefore, we do hide
|
||||||
|
* such windows to prevent them from overlaying other apps.
|
||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public long removeTimeoutMilliseconds = -1;
|
public long hideTimeoutMilliseconds = -1;
|
||||||
|
|
||||||
public LayoutParams() {
|
public LayoutParams() {
|
||||||
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||||
@@ -1895,7 +1899,7 @@ public interface WindowManager extends ViewManager {
|
|||||||
out.writeInt(needsMenuKey);
|
out.writeInt(needsMenuKey);
|
||||||
out.writeInt(accessibilityIdOfAnchor);
|
out.writeInt(accessibilityIdOfAnchor);
|
||||||
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
|
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
|
||||||
out.writeLong(removeTimeoutMilliseconds);
|
out.writeLong(hideTimeoutMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<LayoutParams> CREATOR
|
public static final Parcelable.Creator<LayoutParams> CREATOR
|
||||||
@@ -1949,7 +1953,7 @@ public interface WindowManager extends ViewManager {
|
|||||||
needsMenuKey = in.readInt();
|
needsMenuKey = in.readInt();
|
||||||
accessibilityIdOfAnchor = in.readInt();
|
accessibilityIdOfAnchor = in.readInt();
|
||||||
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||||||
removeTimeoutMilliseconds = in.readLong();
|
hideTimeoutMilliseconds = in.readLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"PointlessBitwiseExpression"})
|
@SuppressWarnings({"PointlessBitwiseExpression"})
|
||||||
@@ -2171,7 +2175,7 @@ public interface WindowManager extends ViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This can't change, it's only set at window creation time.
|
// This can't change, it's only set at window creation time.
|
||||||
removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
|
hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;
|
||||||
|
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import android.content.res.Configuration;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -326,13 +328,6 @@ public class Toast {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class TN extends ITransientNotification.Stub {
|
private static class TN extends ITransientNotification.Stub {
|
||||||
final Runnable mShow = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
handleShow();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final Runnable mHide = new Runnable() {
|
final Runnable mHide = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -343,7 +338,13 @@ public class Toast {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
|
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
|
||||||
final Handler mHandler = new Handler();
|
final Handler mHandler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
IBinder token = (IBinder) msg.obj;
|
||||||
|
handleShow(token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int mGravity;
|
int mGravity;
|
||||||
int mX, mY;
|
int mX, mY;
|
||||||
@@ -379,9 +380,9 @@ public class Toast {
|
|||||||
* schedule handleShow into the right thread
|
* schedule handleShow into the right thread
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void show() {
|
public void show(IBinder windowToken) {
|
||||||
if (localLOGV) Log.v(TAG, "SHOW: " + this);
|
if (localLOGV) Log.v(TAG, "SHOW: " + this);
|
||||||
mHandler.post(mShow);
|
mHandler.obtainMessage(0, windowToken).sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -393,7 +394,7 @@ public class Toast {
|
|||||||
mHandler.post(mHide);
|
mHandler.post(mHide);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleShow() {
|
public void handleShow(IBinder windowToken) {
|
||||||
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
|
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
|
||||||
+ " mNextView=" + mNextView);
|
+ " mNextView=" + mNextView);
|
||||||
if (mView != mNextView) {
|
if (mView != mNextView) {
|
||||||
@@ -422,8 +423,9 @@ public class Toast {
|
|||||||
mParams.verticalMargin = mVerticalMargin;
|
mParams.verticalMargin = mVerticalMargin;
|
||||||
mParams.horizontalMargin = mHorizontalMargin;
|
mParams.horizontalMargin = mHorizontalMargin;
|
||||||
mParams.packageName = packageName;
|
mParams.packageName = packageName;
|
||||||
mParams.removeTimeoutMilliseconds = mDuration ==
|
mParams.hideTimeoutMilliseconds = mDuration ==
|
||||||
Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
|
Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
|
||||||
|
mParams.token = windowToken;
|
||||||
if (mView.getParent() != null) {
|
if (mView.getParent() != null) {
|
||||||
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
|
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
|
||||||
mWM.removeView(mView);
|
mWM.removeView(mView);
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ import android.app.Notification;
|
|||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.NotificationManager.Policy;
|
import android.app.NotificationManager.Policy;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.RemoteInput;
|
|
||||||
import android.app.StatusBarManager;
|
import android.app.StatusBarManager;
|
||||||
import android.app.backup.BackupManager;
|
import android.app.backup.BackupManager;
|
||||||
import android.app.usage.UsageEvents;
|
import android.app.usage.UsageEvents;
|
||||||
@@ -93,7 +92,6 @@ import android.os.IBinder;
|
|||||||
import android.os.IInterface;
|
import android.os.IInterface;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@@ -122,6 +120,8 @@ import android.util.Log;
|
|||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.Xml;
|
import android.util.Xml;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.WindowManagerInternal;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -138,6 +138,7 @@ import com.android.server.SystemService;
|
|||||||
import com.android.server.lights.Light;
|
import com.android.server.lights.Light;
|
||||||
import com.android.server.lights.LightsManager;
|
import com.android.server.lights.LightsManager;
|
||||||
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
|
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
|
||||||
|
import com.android.server.policy.PhoneWindowManager;
|
||||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||||
import com.android.server.vr.VrManagerInternal;
|
import com.android.server.vr.VrManagerInternal;
|
||||||
import com.android.server.notification.ManagedServices.UserProfiles;
|
import com.android.server.notification.ManagedServices.UserProfiles;
|
||||||
@@ -193,7 +194,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
private static final int MESSAGE_RECONSIDER_RANKING = 1000;
|
private static final int MESSAGE_RECONSIDER_RANKING = 1000;
|
||||||
private static final int MESSAGE_RANKING_SORT = 1001;
|
private static final int MESSAGE_RANKING_SORT = 1001;
|
||||||
|
|
||||||
static final int LONG_DELAY = 3500; // 3.5 seconds
|
static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
|
||||||
static final int SHORT_DELAY = 2000; // 2 seconds
|
static final int SHORT_DELAY = 2000; // 2 seconds
|
||||||
|
|
||||||
static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
|
static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
|
||||||
@@ -232,6 +233,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
@Nullable StatusBarManagerInternal mStatusBar;
|
@Nullable StatusBarManagerInternal mStatusBar;
|
||||||
Vibrator mVibrator;
|
Vibrator mVibrator;
|
||||||
private VrManagerInternal mVrManagerInternal;
|
private VrManagerInternal mVrManagerInternal;
|
||||||
|
private WindowManagerInternal mWindowManagerInternal;
|
||||||
|
|
||||||
final IBinder mForegroundToken = new Binder();
|
final IBinder mForegroundToken = new Binder();
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
@@ -452,13 +454,15 @@ public class NotificationManagerService extends SystemService {
|
|||||||
final String pkg;
|
final String pkg;
|
||||||
final ITransientNotification callback;
|
final ITransientNotification callback;
|
||||||
int duration;
|
int duration;
|
||||||
|
Binder token;
|
||||||
|
|
||||||
ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
|
ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
|
||||||
{
|
Binder token) {
|
||||||
this.pid = pid;
|
this.pid = pid;
|
||||||
this.pkg = pkg;
|
this.pkg = pkg;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
|
this.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(int duration) {
|
void update(int duration) {
|
||||||
@@ -1125,6 +1129,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
||||||
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
|
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
|
||||||
mVrManagerInternal = getLocalService(VrManagerInternal.class);
|
mVrManagerInternal = getLocalService(VrManagerInternal.class);
|
||||||
|
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
|
||||||
mZenModeHelper.onSystemReady();
|
mZenModeHelper.onSystemReady();
|
||||||
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
|
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
|
||||||
// This observer will force an update when observe is called, causing us to
|
// This observer will force an update when observe is called, causing us to
|
||||||
@@ -1325,10 +1330,13 @@ public class NotificationManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record = new ToastRecord(callingPid, pkg, callback, duration);
|
Binder token = new Binder();
|
||||||
|
mWindowManagerInternal.addWindowToken(token,
|
||||||
|
WindowManager.LayoutParams.TYPE_TOAST);
|
||||||
|
record = new ToastRecord(callingPid, pkg, callback, duration, token);
|
||||||
mToastQueue.add(record);
|
mToastQueue.add(record);
|
||||||
index = mToastQueue.size() - 1;
|
index = mToastQueue.size() - 1;
|
||||||
keepProcessAliveLocked(callingPid);
|
keepProcessAliveIfNeededLocked(callingPid);
|
||||||
}
|
}
|
||||||
// If it's at index 0, it's the current toast. It doesn't matter if it's
|
// If it's at index 0, it's the current toast. It doesn't matter if it's
|
||||||
// new or just been updated. Call back and tell it to show itself.
|
// new or just been updated. Call back and tell it to show itself.
|
||||||
@@ -2991,7 +2999,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
while (record != null) {
|
while (record != null) {
|
||||||
if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
|
if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
|
||||||
try {
|
try {
|
||||||
record.callback.show();
|
record.callback.show(record.token);
|
||||||
scheduleTimeoutLocked(record);
|
scheduleTimeoutLocked(record);
|
||||||
return;
|
return;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
@@ -3002,7 +3010,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
mToastQueue.remove(index);
|
mToastQueue.remove(index);
|
||||||
}
|
}
|
||||||
keepProcessAliveLocked(record.pid);
|
keepProcessAliveIfNeededLocked(record.pid);
|
||||||
if (mToastQueue.size() > 0) {
|
if (mToastQueue.size() > 0) {
|
||||||
record = mToastQueue.get(0);
|
record = mToastQueue.get(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -3022,8 +3030,11 @@ public class NotificationManagerService extends SystemService {
|
|||||||
// don't worry about this, we're about to remove it from
|
// don't worry about this, we're about to remove it from
|
||||||
// the list anyway
|
// the list anyway
|
||||||
}
|
}
|
||||||
mToastQueue.remove(index);
|
|
||||||
keepProcessAliveLocked(record.pid);
|
ToastRecord lastToast = mToastQueue.remove(index);
|
||||||
|
mWindowManagerInternal.removeWindowToken(lastToast.token, true);
|
||||||
|
|
||||||
|
keepProcessAliveIfNeededLocked(record.pid);
|
||||||
if (mToastQueue.size() > 0) {
|
if (mToastQueue.size() > 0) {
|
||||||
// Show the next one. If the callback fails, this will remove
|
// Show the next one. If the callback fails, this will remove
|
||||||
// it from the list, so don't assume that the list hasn't changed
|
// it from the list, so don't assume that the list hasn't changed
|
||||||
@@ -3067,7 +3078,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// lock on mToastQueue
|
// lock on mToastQueue
|
||||||
void keepProcessAliveLocked(int pid)
|
void keepProcessAliveIfNeededLocked(int pid)
|
||||||
{
|
{
|
||||||
int toastCount = 0; // toasts from this pid
|
int toastCount = 0; // toasts from this pid
|
||||||
ArrayList<ToastRecord> list = mToastQueue;
|
ArrayList<ToastRecord> list = mToastQueue;
|
||||||
|
|||||||
@@ -301,6 +301,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
/** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
|
/** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
|
||||||
static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
|
static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
|
||||||
|
|
||||||
|
/** Amount of time (in milliseconds) a toast window can be shown. */
|
||||||
|
public static final int TOAST_WINDOW_TIMEOUT = 3500; // 3.5 seconds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lock protecting internal state. Must not call out into window
|
* Lock protecting internal state. Must not call out into window
|
||||||
* manager with lock held. (This lock will be acquired in places
|
* manager with lock held. (This lock will be acquired in places
|
||||||
@@ -2229,9 +2232,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
|
attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_SCREENSHOT:
|
case TYPE_SCREENSHOT:
|
||||||
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TYPE_TOAST:
|
||||||
|
// While apps should use the dedicated toast APIs to add such windows
|
||||||
|
// it possible legacy apps to add the window directly. Therefore, we
|
||||||
|
// make windows added directly by the app behave as a toast as much
|
||||||
|
// as possible in terms of timeout and animation.
|
||||||
|
if (attrs.hideTimeoutMilliseconds < 0
|
||||||
|
|| attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
|
||||||
|
attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
|
||||||
|
}
|
||||||
|
attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attrs.type != TYPE_STATUS_BAR) {
|
if (attrs.type != TYPE_STATUS_BAR) {
|
||||||
|
|||||||
@@ -22,14 +22,19 @@ import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
|
|||||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
||||||
|
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
|
||||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
|
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
|
||||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||||
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
|
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
|
||||||
|
|
||||||
import android.app.ActivityManager.StackId;
|
import android.app.ActivityManager.StackId;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
import android.graphics.Region.Op;
|
import android.graphics.Region.Op;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
@@ -684,4 +689,39 @@ class DisplayContent {
|
|||||||
mStacks.get(i).overridePlayingAppAnimations(a);
|
mStacks.get(i).overridePlayingAppAnimations(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean canAddToastWindowForUid(int uid) {
|
||||||
|
// We allow one toast window per UID being shown at a time.
|
||||||
|
WindowList windows = getWindowList();
|
||||||
|
final int windowCount = windows.size();
|
||||||
|
for (int i = 0; i < windowCount; i++) {
|
||||||
|
WindowState window = windows.get(i);
|
||||||
|
if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
|
||||||
|
&& !window.mPermanentlyHidden && !window.mAnimatingExit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
|
||||||
|
WindowState newFocus) {
|
||||||
|
if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int lostFocusUid = oldFocus.mOwnerUid;
|
||||||
|
WindowList windows = getWindowList();
|
||||||
|
final int windowCount = windows.size();
|
||||||
|
for (int i = 0; i < windowCount; i++) {
|
||||||
|
WindowState window = windows.get(i);
|
||||||
|
if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) {
|
||||||
|
if (!mService.mH.hasMessages(WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window)) {
|
||||||
|
mService.mH.sendMessageDelayed(
|
||||||
|
mService.mH.obtainMessage(
|
||||||
|
WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window),
|
||||||
|
window.mAttrs.hideTimeoutMilliseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.CompatibilityInfo;
|
import android.content.res.CompatibilityInfo;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
@@ -201,6 +202,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
|||||||
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
|
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
|
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
|
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
|
||||||
|
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
|
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
|
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
|
||||||
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
|
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
|
||||||
@@ -1869,6 +1871,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
boolean reportNewConfig = false;
|
boolean reportNewConfig = false;
|
||||||
WindowState attachedWindow = null;
|
WindowState attachedWindow = null;
|
||||||
long origId;
|
long origId;
|
||||||
|
final int callingUid = Binder.getCallingUid();
|
||||||
final int type = attrs.type;
|
final int type = attrs.type;
|
||||||
|
|
||||||
synchronized(mWindowMap) {
|
synchronized(mWindowMap) {
|
||||||
@@ -1916,6 +1919,8 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
boolean addToken = false;
|
boolean addToken = false;
|
||||||
WindowToken token = mTokenMap.get(attrs.token);
|
WindowToken token = mTokenMap.get(attrs.token);
|
||||||
AppWindowToken atoken = null;
|
AppWindowToken atoken = null;
|
||||||
|
boolean addToastWindowRequiresToken = false;
|
||||||
|
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
|
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
|
||||||
Slog.w(TAG_WM, "Attempted to add application window with unknown token "
|
Slog.w(TAG_WM, "Attempted to add application window with unknown token "
|
||||||
@@ -1952,6 +1957,15 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
+ attrs.token + ". Aborting.");
|
+ attrs.token + ". Aborting.");
|
||||||
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
|
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
|
||||||
}
|
}
|
||||||
|
if (type == TYPE_TOAST) {
|
||||||
|
// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
|
||||||
|
if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
|
||||||
|
attachedWindow)) {
|
||||||
|
Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
|
||||||
|
+ attrs.token + ". Aborting.");
|
||||||
|
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
token = new WindowToken(this, attrs.token, -1, false);
|
token = new WindowToken(this, attrs.token, -1, false);
|
||||||
addToken = true;
|
addToken = true;
|
||||||
} else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
|
} else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
|
||||||
@@ -2001,6 +2015,15 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
+ attrs.token + ". Aborting.");
|
+ attrs.token + ". Aborting.");
|
||||||
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
|
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
|
||||||
}
|
}
|
||||||
|
} else if (type == TYPE_TOAST) {
|
||||||
|
// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
|
||||||
|
addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
|
||||||
|
callingUid, attachedWindow);
|
||||||
|
if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
|
||||||
|
Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
|
||||||
|
+ attrs.token + ". Aborting.");
|
||||||
|
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
|
||||||
|
}
|
||||||
} else if (type == TYPE_QS_DIALOG) {
|
} else if (type == TYPE_QS_DIALOG) {
|
||||||
if (token.windowType != TYPE_QS_DIALOG) {
|
if (token.windowType != TYPE_QS_DIALOG) {
|
||||||
Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
|
Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
|
||||||
@@ -2045,6 +2068,36 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
win.openInputChannel(outInputChannel);
|
win.openInputChannel(outInputChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If adding a toast requires a token for this app we always schedule hiding
|
||||||
|
// toast windows to make sure they don't stick around longer then necessary.
|
||||||
|
// We hide instead of remove such windows as apps aren't prepared to handle
|
||||||
|
// windows being removed under them.
|
||||||
|
//
|
||||||
|
// If the app is older it can add toasts without a token and hence overlay
|
||||||
|
// other apps. To be maximally compatible with these apps we will hide the
|
||||||
|
// window after the toast timeout only if the focused window is from another
|
||||||
|
// UID, otherwise we allow unlimited duration. When a UID looses focus we
|
||||||
|
// schedule hiding all of its toast windows.
|
||||||
|
if (type == TYPE_TOAST) {
|
||||||
|
if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
|
||||||
|
Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
|
||||||
|
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
|
||||||
|
}
|
||||||
|
// Make sure this happens before we moved focus as one can make the
|
||||||
|
// toast focusable to force it not being hidden after the timeout.
|
||||||
|
// Focusable toasts are always timed out to prevent a focused app to
|
||||||
|
// show a focusable toasts while it has focus which will be kept on
|
||||||
|
// the screen after the activity goes away.
|
||||||
|
if (addToastWindowRequiresToken
|
||||||
|
|| (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
|
||||||
|
|| mCurrentFocus == null
|
||||||
|
|| mCurrentFocus.mOwnerUid != callingUid) {
|
||||||
|
mH.sendMessageDelayed(
|
||||||
|
mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
|
||||||
|
win.mAttrs.hideTimeoutMilliseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// From now on, no exceptions or errors allowed!
|
// From now on, no exceptions or errors allowed!
|
||||||
|
|
||||||
res = WindowManagerGlobal.ADD_OKAY;
|
res = WindowManagerGlobal.ADD_OKAY;
|
||||||
@@ -2183,11 +2236,6 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
|
if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
|
||||||
reportNewConfig = true;
|
reportNewConfig = true;
|
||||||
}
|
}
|
||||||
if (attrs.removeTimeoutMilliseconds > 0) {
|
|
||||||
mH.sendMessageDelayed(
|
|
||||||
mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
|
|
||||||
attrs.removeTimeoutMilliseconds);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reportNewConfig) {
|
if (reportNewConfig) {
|
||||||
@@ -2199,6 +2247,32 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
|
||||||
|
WindowState attachedWindow) {
|
||||||
|
// Try using the target SDK of the root window
|
||||||
|
if (attachedWindow != null) {
|
||||||
|
return attachedWindow.mAppToken != null
|
||||||
|
&& attachedWindow.mAppToken.targetSdk > Build.VERSION_CODES.N_MR1;
|
||||||
|
} else {
|
||||||
|
// Otherwise, look at the package
|
||||||
|
try {
|
||||||
|
ApplicationInfo appInfo = mContext.getPackageManager()
|
||||||
|
.getApplicationInfoAsUser(packageName, 0,
|
||||||
|
UserHandle.getUserId(callingUid));
|
||||||
|
if (appInfo.uid != callingUid) {
|
||||||
|
throw new SecurityException("Package " + packageName + " not in UID "
|
||||||
|
+ callingUid);
|
||||||
|
}
|
||||||
|
if (appInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if we're done setting up any transitions.
|
* Returns true if we're done setting up any transitions.
|
||||||
*/
|
*/
|
||||||
@@ -8165,7 +8239,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
|
public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
|
||||||
public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
|
public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
|
||||||
public static final int UPDATE_ANIMATION_SCALE = 51;
|
public static final int UPDATE_ANIMATION_SCALE = 51;
|
||||||
public static final int WINDOW_REMOVE_TIMEOUT = 52;
|
public static final int WINDOW_HIDE_TIMEOUT = 52;
|
||||||
public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
|
public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
|
||||||
public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
|
public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
|
||||||
|
|
||||||
@@ -8785,7 +8859,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
mAmInternal.notifyStartingWindowDrawn();
|
mAmInternal.notifyStartingWindowDrawn();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WINDOW_REMOVE_TIMEOUT: {
|
case WINDOW_HIDE_TIMEOUT: {
|
||||||
final WindowState window = (WindowState) msg.obj;
|
final WindowState window = (WindowState) msg.obj;
|
||||||
synchronized(mWindowMap) {
|
synchronized(mWindowMap) {
|
||||||
// TODO: This is all about fixing b/21693547
|
// TODO: This is all about fixing b/21693547
|
||||||
@@ -8796,8 +8870,11 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
// running under debugger) to crash (b/29105388). The windows will
|
// running under debugger) to crash (b/29105388). The windows will
|
||||||
// eventually be removed when the client process finishes.
|
// eventually be removed when the client process finishes.
|
||||||
// The best we can do for now is remove the FLAG_KEEP_SCREEN_ON
|
// The best we can do for now is remove the FLAG_KEEP_SCREEN_ON
|
||||||
// and prevent the symptoms of b/21693547.
|
// and prevent the symptoms of b/21693547. Since apps don't
|
||||||
|
// support windows being removed under them we hide the window
|
||||||
|
// and it will be removed when the app dies.
|
||||||
window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
|
window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
|
||||||
|
window.hidePermanentlyLw();
|
||||||
window.setDisplayLayoutNeeded();
|
window.setDisplayLayoutNeeded();
|
||||||
mWindowPlacerLocked.performSurfacePlacement();
|
mWindowPlacerLocked.performSurfacePlacement();
|
||||||
}
|
}
|
||||||
@@ -9833,6 +9910,12 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
|
|
||||||
adjustForImeIfNeeded(displayContent);
|
adjustForImeIfNeeded(displayContent);
|
||||||
|
|
||||||
|
// We may need to schedule some toast windows to be removed. The
|
||||||
|
// toasts for an app that does not have input focus are removed
|
||||||
|
// within a timeout to prevent apps to redress other apps' UI.
|
||||||
|
oldFocus.getDisplayContent().scheduleToastWindowsTimeoutIfNeededLocked(
|
||||||
|
oldFocus, newFocus);
|
||||||
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
|
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
|
|||||||
boolean mPolicyVisibility = true;
|
boolean mPolicyVisibility = true;
|
||||||
boolean mPolicyVisibilityAfterAnim = true;
|
boolean mPolicyVisibilityAfterAnim = true;
|
||||||
boolean mAppOpVisibility = true;
|
boolean mAppOpVisibility = true;
|
||||||
|
boolean mPermanentlyHidden; // the window should never be shown again
|
||||||
boolean mAppFreezing;
|
boolean mAppFreezing;
|
||||||
boolean mAttachedHidden; // is our parent window hidden?
|
boolean mAttachedHidden; // is our parent window hidden?
|
||||||
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
|
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
|
||||||
@@ -1876,6 +1877,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
|
|||||||
// Being hidden due to app op request.
|
// Being hidden due to app op request.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (mPermanentlyHidden) {
|
||||||
|
// Permanently hidden until the app exists as apps aren't prepared
|
||||||
|
// to handle their windows being removed from under them.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
|
if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
|
||||||
// Already showing.
|
// Already showing.
|
||||||
return false;
|
return false;
|
||||||
@@ -1966,6 +1972,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void hidePermanentlyLw() {
|
||||||
|
if (!mPermanentlyHidden) {
|
||||||
|
mPermanentlyHidden = true;
|
||||||
|
hideLw(true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void pokeDrawLockLw(long timeout) {
|
public void pokeDrawLockLw(long timeout) {
|
||||||
if (isVisibleOrAdding()) {
|
if (isVisibleOrAdding()) {
|
||||||
if (mDrawLock == null) {
|
if (mDrawLock == null) {
|
||||||
@@ -2615,7 +2628,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
|
|||||||
pw.println(Integer.toHexString(mSystemUiVisibility));
|
pw.println(Integer.toHexString(mSystemUiVisibility));
|
||||||
}
|
}
|
||||||
if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
|
if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
|
||||||
|| mAttachedHidden) {
|
|| mAttachedHidden || mPermanentlyHidden) {
|
||||||
pw.print(prefix); pw.print("mPolicyVisibility=");
|
pw.print(prefix); pw.print("mPolicyVisibility=");
|
||||||
pw.print(mPolicyVisibility);
|
pw.print(mPolicyVisibility);
|
||||||
pw.print(" mPolicyVisibilityAfterAnim=");
|
pw.print(" mPolicyVisibilityAfterAnim=");
|
||||||
@@ -2623,6 +2636,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
|
|||||||
pw.print(" mAppOpVisibility=");
|
pw.print(" mAppOpVisibility=");
|
||||||
pw.print(mAppOpVisibility);
|
pw.print(mAppOpVisibility);
|
||||||
pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
|
pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
|
||||||
|
pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
|
||||||
}
|
}
|
||||||
if (!mRelayoutCalled || mLayoutNeeded) {
|
if (!mRelayoutCalled || mLayoutNeeded) {
|
||||||
pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
|
pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
|
||||||
|
|||||||
Reference in New Issue
Block a user