Show toasts from system/sysUI to all users
The package name test is safe:
* If it's used by Toast class in an app, apps have access to layout
params anyway via getWindowParams() and applied flag is already
protected by INTERNAL_SYSTEM_WINDOW permission.
* If it's used by ToastUI class in sys UI on behalf of another app,
sys UI is trusted domain and can't be messed up by another app. It
also has INTERNAL_SYSTEM_WINDOW permission.
Bug: 149408635
Test: atest ToastUITest android.widget.cts.ToastTest
android.widget.cts29.ToastTest android.server.wm.ToastTest
Test: Change phone to vibration/silent in secondary user and observe
toast is displayed.
Change-Id: I227e9f74166300fcb3ba8f3871b464afe6ec6a28
Merged-In: I227e9f74166300fcb3ba8f3871b464afe6ec6a28
(cherry picked from commit caef507aa9)
This commit is contained in:
@@ -651,7 +651,7 @@ public class Toast {
|
||||
}
|
||||
};
|
||||
|
||||
presenter.startLayoutParams(mParams);
|
||||
presenter.startLayoutParams(mParams, packageName);
|
||||
}
|
||||
|
||||
private List<Callback> getCallbacks() {
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.IBinder;
|
||||
import android.view.Gravity;
|
||||
@@ -28,6 +29,7 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
/**
|
||||
* Class responsible for toast presentation inside app's process and in system UI.
|
||||
@@ -39,17 +41,19 @@ public class ToastPresenter {
|
||||
private static final long LONG_DURATION_TIMEOUT = 7000;
|
||||
|
||||
private final Context mContext;
|
||||
private final Resources mResources;
|
||||
private final AccessibilityManager mAccessibilityManager;
|
||||
|
||||
public ToastPresenter(Context context, AccessibilityManager accessibilityManager) {
|
||||
mContext = context;
|
||||
mResources = context.getResources();
|
||||
mAccessibilityManager = accessibilityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes {@code params} with default values for toasts.
|
||||
*/
|
||||
public void startLayoutParams(WindowManager.LayoutParams params) {
|
||||
public void startLayoutParams(WindowManager.LayoutParams params, String packageName) {
|
||||
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.format = PixelFormat.TRANSLUCENT;
|
||||
@@ -60,6 +64,7 @@ public class ToastPresenter {
|
||||
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||
setShowForAllUsersIfApplicable(params, packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +74,7 @@ public class ToastPresenter {
|
||||
public void adjustLayoutParams(WindowManager.LayoutParams params, IBinder windowToken,
|
||||
int duration, int gravity, int xOffset, int yOffset, float horizontalMargin,
|
||||
float verticalMargin) {
|
||||
Configuration config = mContext.getResources().getConfiguration();
|
||||
Configuration config = mResources.getConfiguration();
|
||||
int absGravity = Gravity.getAbsoluteGravity(gravity, config.getLayoutDirection());
|
||||
params.gravity = absGravity;
|
||||
if ((absGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
|
||||
@@ -88,6 +93,32 @@ public class ToastPresenter {
|
||||
params.token = windowToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link WindowManager.LayoutParams#SYSTEM_FLAG_SHOW_FOR_ALL_USERS} flag if {@code
|
||||
* packageName} is a cross-user package.
|
||||
*
|
||||
* Implementation note:
|
||||
* This code is safe to be executed in SystemUI and the app's process:
|
||||
* <li>SystemUI: It's running on a trusted domain so apps can't tamper with it. SystemUI
|
||||
* has the permission INTERNAL_SYSTEM_WINDOW needed by the flag, so SystemUI can add
|
||||
* the flag on behalf of those packages, which all contain INTERNAL_SYSTEM_WINDOW
|
||||
* permission.
|
||||
* <li>App: The flag being added is protected behind INTERNAL_SYSTEM_WINDOW permission
|
||||
* and any app can already add that flag via getWindowParams() if it has that
|
||||
* permission, so we are just doing this automatically for cross-user packages.
|
||||
*/
|
||||
private void setShowForAllUsersIfApplicable(WindowManager.LayoutParams params,
|
||||
String packageName) {
|
||||
if (isCrossUserPackage(packageName)) {
|
||||
params.privateFlags = WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCrossUserPackage(String packageName) {
|
||||
String[] packages = mResources.getStringArray(R.array.config_toastCrossUserPackages);
|
||||
return ArrayUtils.contains(packages, packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default text toast view for message {@code text}.
|
||||
*/
|
||||
|
||||
@@ -4410,4 +4410,13 @@
|
||||
|
||||
<!-- Whether to default to an expanded list of users on the lock screen user switcher. -->
|
||||
<bool name="config_expandLockScreenUserSwitcher">false</bool>
|
||||
|
||||
<!-- Toasts posted from these packages will be shown to the current user, regardless of the user
|
||||
the process belongs to. This is useful for packages that run under a single user but serve
|
||||
multiple users, e.g. the system.
|
||||
These packages MUST be able to add flag SYSTEM_FLAG_SHOW_FOR_ALL_USERS to a window. -->
|
||||
<string-array name="config_toastCrossUserPackages" translatable="false">
|
||||
<item>android</item>
|
||||
<item>com.android.systemui</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -3903,4 +3903,6 @@
|
||||
<java-symbol type="bool" name="config_expandLockScreenUserSwitcher" />
|
||||
|
||||
<java-symbol type="string" name="loading" />
|
||||
|
||||
<java-symbol type="array" name="config_toastCrossUserPackages" />
|
||||
</resources>
|
||||
|
||||
@@ -95,7 +95,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
|
||||
hideCurrentToast();
|
||||
}
|
||||
View view = mPresenter.getTextToastView(text);
|
||||
LayoutParams params = getLayoutParams(windowToken, duration);
|
||||
LayoutParams params = getLayoutParams(packageName, windowToken, duration);
|
||||
mCurrentToast = new ToastEntry(packageName, token, view, windowToken, callback);
|
||||
try {
|
||||
mWindowManager.addView(view, params);
|
||||
@@ -145,9 +145,9 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
|
||||
mCurrentToast = null;
|
||||
}
|
||||
|
||||
private LayoutParams getLayoutParams(IBinder windowToken, int duration) {
|
||||
private LayoutParams getLayoutParams(String packageName, IBinder windowToken, int duration) {
|
||||
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
|
||||
mPresenter.startLayoutParams(params);
|
||||
mPresenter.startLayoutParams(params, packageName);
|
||||
int gravity = mContext.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_toastDefaultGravity);
|
||||
int yOffset = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
|
||||
|
||||
@@ -105,6 +105,33 @@ public class ToastUITest extends SysuiTestCase {
|
||||
assertThat(windowParams.packageName).isEqualTo(mContext.getPackageName());
|
||||
assertThat(windowParams.getTitle()).isEqualTo("Toast");
|
||||
assertThat(windowParams.token).isEqualTo(WINDOW_TOKEN_1);
|
||||
assertThat(windowParams.privateFlags
|
||||
& WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowToast_forAndroidPackage_addsAllUserFlag() throws Exception {
|
||||
mToastUI.showToast("android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
|
||||
|
||||
verify(mWindowManager).addView(any(), mParamsCaptor.capture());
|
||||
ViewGroup.LayoutParams params = mParamsCaptor.getValue();
|
||||
assertThat(params).isInstanceOf(WindowManager.LayoutParams.class);
|
||||
WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
|
||||
assertThat(windowParams.privateFlags
|
||||
& WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS).isNotEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowToast_forSystemUiPackage_addsAllUserFlag() throws Exception {
|
||||
mToastUI.showToast("com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
|
||||
null);
|
||||
|
||||
verify(mWindowManager).addView(any(), mParamsCaptor.capture());
|
||||
ViewGroup.LayoutParams params = mParamsCaptor.getValue();
|
||||
assertThat(params).isInstanceOf(WindowManager.LayoutParams.class);
|
||||
WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
|
||||
assertThat(windowParams.privateFlags
|
||||
& WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS).isNotEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user