Merge "Allow config context to inflate views" into sc-dev
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -2260,6 +2261,44 @@ public final class StrictMode {
|
||||
onVmPolicyViolation(new IncorrectContextUseViolation(message, originStack));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -950,4 +950,10 @@ public class MockContext extends Context {
|
||||
public boolean isUiContext() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
@Override
|
||||
public boolean isConfigurationContext() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user