summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorCharles Chen <charlesccchen@google.com>2021-04-09 06:56:16 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-04-09 06:56:16 +0000
commitc22aff4e4d4de8fcb95e1544db952aa1bdfd999a (patch)
tree8cf9b6f59d3ea3877d863f220ea57df84a598a27 /core/java/android
parent0584a987a47fbca8ca8c76bd579f81ad19c693da (diff)
parentd12be75275d2b4e244e72c4382720b76a53d1084 (diff)
Merge "Allow config context to inflate views" into sc-dev
Diffstat (limited to 'core/java/android')
-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
7 files changed, 99 insertions, 38 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 89312f4b3837..ec7d159f707b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -243,6 +243,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;
@@ -2002,13 +2005,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);
@@ -2041,6 +2043,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.
@@ -2053,10 +2061,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) {
@@ -2538,6 +2542,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
@@ -2575,6 +2580,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;
}
@@ -2988,6 +2997,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;
@@ -3058,6 +3068,7 @@ class ContextImpl extends Context {
setResources(container.mResources);
mDisplay = container.mDisplay;
mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
+ mIsConfigurationBasedContext = container.mIsConfigurationBasedContext;
mContextType = container.mContextType;
} else {
mBasePackageName = packageInfo.mPackageName;
@@ -3135,6 +3146,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 36769825c439..5fd85613c7ef 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6817,4 +6817,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);