summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ContextImpl.java28
-rw-r--r--core/java/android/content/Context.java21
-rw-r--r--core/java/android/content/ContextWrapper.java11
-rw-r--r--core/java/android/os/StrictMode.java39
-rw-r--r--core/java/android/view/GestureDetector.java16
-rw-r--r--core/java/android/view/LayoutInflater.java4
-rw-r--r--core/java/android/view/ViewConfiguration.java18
-rw-r--r--test-mock/src/android/test/mock/MockContext.java6
8 files changed, 105 insertions, 38 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index eb31b5294a26..388c7b9f6cdc 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -242,6 +242,9 @@ class ContextImpl extends Context {
*/
private boolean mForceDisplayOverrideInResources;
+ /** @see Context#isConfigurationContext() */
+ private boolean mIsConfigurationBasedContext;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mFlags;
@@ -2001,13 +2004,12 @@ class ContextImpl extends Context {
public Object getSystemService(String name) {
if (vmIncorrectContextUseEnabled()) {
// Check incorrect Context usage.
- if (isUiComponent(name) && !isUiContext()) {
+ if (WINDOW_SERVICE.equals(name) && !isUiContext()) {
final String errorMessage = "Tried to access visual service "
+ SystemServiceRegistry.getSystemServiceClassName(name)
+ " from a non-visual Context:" + getOuterContext();
- final String message = "Visual services, such as WindowManager "
- + "or LayoutInflater should be accessed from Activity or another visual "
- + "Context. Use an Activity or a Context created with "
+ final String message = "WindowManager should 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 IllegalAccessException(errorMessage);
@@ -2040,6 +2042,12 @@ class ContextImpl extends Context {
}
}
+ /** @hide */
+ @Override
+ public boolean isConfigurationContext() {
+ return isUiContext() || mIsConfigurationBasedContext;
+ }
+
/**
* Temporary workaround to permit incorrect usages of Context by SystemUI.
* TODO(b/147647877): Fix usages and remove.
@@ -2052,10 +2060,6 @@ class ContextImpl extends Context {
Binder.getCallingUid()) == PERMISSION_GRANTED;
}
- private static boolean isUiComponent(String name) {
- return WINDOW_SERVICE.equals(name) || LAYOUT_INFLATER_SERVICE.equals(name);
- }
-
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
@@ -2537,6 +2541,7 @@ class ContextImpl extends Context {
mAttributionSource.getAttributionTag(),
mAttributionSource.getNext(),
mSplitName, mToken, mUser, mFlags, mClassLoader, null);
+ context.mIsConfigurationBasedContext = true;
final int displayId = getDisplayId();
final Integer overrideDisplayId = mForceDisplayOverrideInResources
@@ -2574,6 +2579,10 @@ class ContextImpl extends Context {
// the display that would otherwise be inherited from mToken (or the global configuration if
// mToken is null).
context.mForceDisplayOverrideInResources = true;
+ // The configuration is overridden by display adjustments' configuration and won't receive
+ // configuration changes. This context won't be regarded as having the proper configuration
+ // anymore.
+ context.mIsConfigurationBasedContext = false;
return context;
}
@@ -2987,6 +2996,7 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
null, null, activityInfo.splitName, activityToken, null, 0, classLoader, null);
context.mContextType = CONTEXT_TYPE_ACTIVITY;
+ context.mIsConfigurationBasedContext = true;
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
@@ -3057,6 +3067,7 @@ class ContextImpl extends Context {
setResources(container.mResources);
mDisplay = container.mDisplay;
mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
+ mIsConfigurationBasedContext = container.mIsConfigurationBasedContext;
mContextType = container.mContextType;
} else {
mBasePackageName = packageInfo.mPackageName;
@@ -3132,6 +3143,7 @@ class ContextImpl extends Context {
// WindowContext.
if (mOuterContext.isUiContext() && mContextType <= CONTEXT_TYPE_DISPLAY_CONTEXT) {
mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
+ mIsConfigurationBasedContext = true;
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 232daa8f8b47..6d08c34f9176 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6816,4 +6816,25 @@ public abstract class Context {
* @hide
*/
public void destroy() { }
+
+ /**
+ * Indicates this {@link Context} has the proper {@link Configuration} to obtain
+ * {@link android.view.LayoutInflater}, {@link android.view.ViewConfiguration} and
+ * {@link android.view.GestureDetector}. Generally, all UI contexts, such as
+ * {@link android.app.Activity} or {@link android.app.WindowContext}, are initialized with base
+ * configuration.
+ * <p>
+ * Note that the context created via {@link Context#createConfigurationContext(Configuration)}
+ * is also regarded as a context that is based on a configuration because the
+ * configuration is explicitly provided via the API.
+ * </p>
+ *
+ * @see #isUiContext()
+ * @see #createConfigurationContext(Configuration)
+ *
+ * @hide
+ */
+ public boolean isConfigurationContext() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index de0d65fec1fb..8936d0c47a58 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1250,4 +1250,15 @@ public class ContextWrapper extends Context {
}
return mBase.isUiContext();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isConfigurationContext() {
+ if (mBase == null) {
+ return false;
+ }
+ return mBase.isConfigurationContext();
+ }
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index df24baaf8ad9..44c3d61b8760 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -30,6 +30,7 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.storage.IStorageManager;
@@ -2261,6 +2262,44 @@ public final class StrictMode {
}
/**
+ * A helper method to verify if the {@code context} has a proper {@link Configuration} to obtain
+ * {@link android.view.LayoutInflater}, {@link android.view.ViewConfiguration} or
+ * {@link android.view.GestureDetector}. Throw {@link IncorrectContextUseViolation} if the
+ * {@code context} doesn't have a proper configuration.
+ * <p>
+ * Note that the context created via {@link Context#createConfigurationContext(Configuration)}
+ * is also regarded as a context with a proper configuration because the {@link Configuration}
+ * is handled by developers.
+ * </p>
+ * @param context The context to verify if it is a display associative context
+ * @param methodName The asserted method name
+ *
+ * @see Context#isConfigurationContext()
+ * @see Context#createConfigurationContext(Configuration)
+ * @see Context#getSystemService(String)
+ * @see Context#LAYOUT_INFLATER_SERVICE
+ * @see android.view.ViewConfiguration#get(Context)
+ * @see android.view.LayoutInflater#from(Context)
+ * @see IncorrectContextUseViolation
+ *
+ * @hide
+ */
+ public static void assertConfigurationContext(@NonNull Context context,
+ @NonNull String methodName) {
+ if (vmIncorrectContextUseEnabled() && !context.isConfigurationContext()) {
+ final String errorMessage = "Tried to access the API:" + methodName + " which needs to"
+ + " have proper configuration from a non-UI Context:" + context;
+ final String message = "The API:" + methodName + " needs a proper configuration."
+ + " Use UI contexts such as an activity or a context created"
+ + " via createWindowContext(Display, int, Bundle) or "
+ + " createConfigurationContext(Configuration) with a proper configuration.";
+ final Exception exception = new IllegalAccessException(errorMessage);
+ StrictMode.onIncorrectContextUsed(message, exception);
+ Log.e(TAG, errorMessage + " " + message, exception);
+ }
+ }
+
+ /**
* A helper method to verify if the {@code context} is a UI context and throw
* {@link IncorrectContextUseViolation} if the {@code context} is not a UI context.
*
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 8a722184eb77..63a8300ce6aa 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -16,8 +16,6 @@
package android.view;
-import static android.os.StrictMode.vmIncorrectContextUseEnabled;
-
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DOUBLE_TAP;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS;
@@ -34,7 +32,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
-import android.util.Log;
import com.android.internal.util.FrameworkStatsLog;
@@ -394,6 +391,7 @@ public class GestureDetector {
*
* @throws NullPointerException if {@code listener} is null.
*/
+ // TODO(b/182007470): Use @ConfigurationContext instead
public GestureDetector(@UiContext Context context, OnGestureListener listener) {
this(context, listener, null);
}
@@ -467,17 +465,7 @@ public class GestureDetector {
mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity();
mAmbiguousGestureMultiplier = ViewConfiguration.getAmbiguousGestureMultiplier();
} else {
- if (!context.isUiContext() && vmIncorrectContextUseEnabled()) {
- final String errorMessage =
- "Tried to access UI constants from a non-visual Context.";
- final String message = "GestureDetector 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);
- }
+ StrictMode.assertConfigurationContext(context, "GestureDetector#init");
final ViewConfiguration configuration = ViewConfiguration.get(context);
touchSlop = configuration.getScaledTouchSlop();
doubleTapTouchSlop = configuration.getScaledDoubleTapTouchSlop();
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 66c514824e35..df78827534a6 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -32,6 +32,7 @@ import android.graphics.Canvas;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
+import android.os.StrictMode;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
@@ -94,6 +95,7 @@ public abstract class LayoutInflater {
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
+ // TODO(b/182007470): Use @ConfigurationContext instead
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@UiContext
protected final Context mContext;
@@ -255,6 +257,7 @@ public abstract class LayoutInflater {
* values for their attributes are retrieved.
*/
protected LayoutInflater(Context context) {
+ StrictMode.assertConfigurationContext(context, "LayoutInflater");
mContext = context;
initPrecompiledViews();
}
@@ -268,6 +271,7 @@ public abstract class LayoutInflater {
* @param newContext The new Context to use.
*/
protected LayoutInflater(LayoutInflater original, Context newContext) {
+ StrictMode.assertConfigurationContext(newContext, "LayoutInflater");
mContext = newContext;
mFactory = original.mFactory;
mFactory2 = original.mFactory2;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index ec23a29b2070..0a3d0da6da1e 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -16,8 +16,6 @@
package android.view;
-import static android.os.StrictMode.vmIncorrectContextUseEnabled;
-
import android.annotation.FloatRange;
import android.annotation.TestApi;
import android.annotation.UiContext;
@@ -34,7 +32,6 @@ 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;
@@ -520,20 +517,9 @@ public class ViewConfiguration {
* be {@link Activity} or other {@link Context} created with
* {@link Context#createWindowContext(int, Bundle)}.
*/
-
+ // TODO(b/182007470): Use @ConfigurationContext instead
public static ViewConfiguration get(@UiContext Context context) {
- if (!context.isUiContext() && vmIncorrectContextUseEnabled()) {
- final String errorMessage = "Tried to access UI constants from a non-visual Context:"
- + 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);
- }
+ StrictMode.assertConfigurationContext(context, "ViewConfiguration");
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
final int density = (int) (100.0f * metrics.density);
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 5391bd8642d5..65aa9aed8f99 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -950,4 +950,10 @@ public class MockContext extends Context {
public boolean isUiContext() {
throw new UnsupportedOperationException();
}
+
+ /** {@hide} */
+ @Override
+ public boolean isConfigurationContext() {
+ throw new UnsupportedOperationException();
+ }
}