Report incorrect context usage in ViewConfiguration

Before, the documentation said that the passed context is an application context, which is incorrect to get the density, window metrics, and window manager. We should use visual context to get these instead.

Bug: 151474461
Test: StrictModeTest#testIncorrectContextUse_GetViewConfiguration
Change-Id: Iea28d727cafbb3ec8536742c6a0e594f73fe5a51
This commit is contained in:
Chris Li
2020-03-17 10:12:24 -07:00
parent 2279fd5f46
commit bfe1b70fcd
5 changed files with 57 additions and 8 deletions

View File

@@ -1920,7 +1920,9 @@ class ContextImpl extends Context {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
private boolean isUiContext() {
/** @hide */
@Override
public boolean isUiContext() {
return mIsSystemOrSystemUiContext || mIsUiContext || isSystemOrSystemUI();
}

View File

@@ -6103,4 +6103,13 @@ public abstract class Context {
+ "get a UI context from ActivityThread#getSystemUiContext()");
}
}
/**
* Indicates if this context is a visual context such as {@link android.app.Activity} or
* a context created from {@link #createWindowContext(int, Bundle)}.
* @hide
*/
public boolean isUiContext() {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
}

View File

@@ -1145,4 +1145,12 @@ public class ContextWrapper extends Context {
mBase.setContentCaptureOptions(options);
}
}
/**
* @hide
*/
@Override
public boolean isUiContext() {
return mBase.isUiContext();
}
}

View File

@@ -16,8 +16,11 @@
package android.view;
import static android.os.StrictMode.vmIncorrectContextUseEnabled;
import android.annotation.FloatRange;
import android.annotation.TestApi;
import android.app.Activity;
import android.app.AppGlobals;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -25,9 +28,12 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.StrictMode;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -35,6 +41,8 @@ import android.util.TypedValue;
* Contains methods to standard constants used in the UI for timeouts, sizes, and distances.
*/
public class ViewConfiguration {
private static final String TAG = "ViewConfiguration";
/**
* Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
* dips
@@ -372,11 +380,13 @@ public class ViewConfiguration {
}
/**
* Creates a new configuration for the specified context. The configuration depends on
* various parameters of the context, like the dimension of the display or the density
* of the display.
* Creates a new configuration for the specified visual {@link Context}. The configuration
* depends on various parameters of the {@link Context}, like the dimension of the display or
* the density of the display.
*
* @param context The application context used to initialize this view configuration.
* @param context A visual {@link Context} used to initialize the view configuration. It must
* be {@link Activity} or other {@link Context} created with
* {@link Context#createWindowContext(int, Bundle)}.
*
* @see #get(android.content.Context)
* @see android.util.DisplayMetrics
@@ -480,13 +490,27 @@ public class ViewConfiguration {
}
/**
* Returns a configuration for the specified context. The configuration depends on
* various parameters of the context, like the dimension of the display or the
* Returns a configuration for the specified visual {@link Context}. The configuration depends
* on various parameters of the {@link Context}, like the dimension of the display or the
* density of the display.
*
* @param context The application context used to initialize the view configuration.
* @param context A visual {@link Context} used to initialize the view configuration. It must
* be {@link Activity} or other {@link Context} created with
* {@link Context#createWindowContext(int, Bundle)}.
*/
public static ViewConfiguration get(Context context) {
if (!context.isUiContext() && vmIncorrectContextUseEnabled()) {
final String errorMessage = "Tried to access UI constants from a non-visual Context.";
final String message = "UI constants, such as display metrics or window metrics, "
+ "must be accessed from Activity or other visual Context. "
+ "Use an Activity or a Context created with "
+ "Context#createWindowContext(int, Bundle), which are adjusted to the "
+ "configuration and visual bounds of an area on screen.";
final Exception exception = new IllegalArgumentException(errorMessage);
StrictMode.onIncorrectContextUsed(message, exception);
Log.e(TAG, errorMessage + message, exception);
}
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
final int density = (int) (100.0f * metrics.density);

View File

@@ -928,4 +928,10 @@ public class MockContext extends Context {
public Handler getMainThreadHandler() {
throw new UnsupportedOperationException();
}
/** {@hide} */
@Override
public boolean isUiContext() {
throw new UnsupportedOperationException();
}
}